WPF:我如何设置我的模型和绑定策略?

发布于 2024-09-06 10:59:20 字数 2141 浏览 3 评论 0原文

看看这张图片: 替代文本 http://img25.imageshack.us/img25/9743/timetablepo.png< /a>

该用户界面的 TimeTableViewModel 是这样的:

public string SchoolclassCodeMonday {get;set;}
public string SchoolclassCodeTuesday {get;set;}
public string SchoolclassCodeWednesday {get;set;}
public string SchoolclassCodeThursday {get;set;}
public string SchoolclassCodeFriday {get;set;}
public string SchoolclassCodeSaturday {get;set;}
public string SchoolclassCodeSunday {get;set;}

当我在文本框中仅将属性显示为字符串时,上述内容将起作用。 但我想要的是将每个组合框绑定到相互ObservableCollection SchoolclassCodes 和 ComboBox 的 SelectedItem 又名 DisplayMember 必须以某种方式 映射到上述 7 个属性之一,并且 SelectedItem(如果检索)必须提供一行 在组合框中选择的所有 7 个班级中。

或者换句话说,我真正想要的;-)

在组合框中显示 SchoolclassCodes 列表,将 SelectedItem.SchoolclassCode"WeekdayName" 的设置为所选值 ComboboxItem.SchoolclassCode

嗯,我有一些想法,但都缺乏一些经验来使它们充分发挥作用。

我可以为每个 Property 添加一个 ObservableCollectionTimeTableViewModelSchoolclassCodes 但这对我来说似乎非常多余。当每个单元格都有相同的列表且其中包含相同的项目时,为什么我应该为一行保留 7 个列表?

欢迎任何有关 ViewModels 结构和 Wpf 中的绑定的建议:)

更新:我的 SchoolclassCodes 列表是动态创建的,因此不可能有静态绑定或硬编码字符串XAML 中的项目...

UPDATE2:

好的,我尝试使其与 MVVM 一起使用:

我必须更改 ObservableCollection ClassCodes ObservableCollection SchoolclassCodes 作为 Schoolclass 对象 有一个对 Pupil 类的引用,其中包含字符串,这是不可能的。

Schoolclass.cs:

public string SchoolclassCode {get;set;}
...

TimeTableWeekViewModel.cs:

public ObservableCollection<Schoolclass> SchoolclassCodes
    {
        get { return _schoolclassCodes; }
        set
        {
            _schoolclassCodes = value;
            this.RaisePropertyChanged("SchoolclassCodes");
        }
    }

XAML:

因为 wpf 找不到 SchoolclassCodes,所以绑定现在必须是什么样子?

Regard this image:
alt text http://img25.imageshack.us/img25/9743/timetablepo.png

The TimeTableViewModel of this user interface is this:

public string SchoolclassCodeMonday {get;set;}
public string SchoolclassCodeTuesday {get;set;}
public string SchoolclassCodeWednesday {get;set;}
public string SchoolclassCodeThursday {get;set;}
public string SchoolclassCodeFriday {get;set;}
public string SchoolclassCodeSaturday {get;set;}
public string SchoolclassCodeSunday {get;set;}

The above would work when I would display only the properties as string in a textbox.
But what I want is to bind each combox to a mutual ObservableCollection
SchoolclassCodes and the SelectedItem aka DisplayMember of the ComboBox must somehow be
MAPPED to one of the 7 above Properties AND the SelectedItem if retrieved must supply a row
of all 7 schoolclass selected in the combobox.

Or what I actually want just in other words ;-)

Display in the ComboBox the SchoolclassCodes list, set the Value of SelectedItem.SchoolclassCode"WeekdayName" to the Value of the selected ComboboxItem.SchoolclassCode

Well there are some ideas I have but all lack some experience to make them fully working.

I could add to the TimeTableViewModel for each Property a ObservableCollection
SchoolclassCodes but that seems very redundant to me. Why should I hold 7 lists for ONE row when each cell has the same list with the same items in it ?

Any suggestions concerning the ViewModels structure and the binding in Wpf are welcome :)

UPDATE: My SchoolclassCodes list is dynamically created, so I there is no possibility about static binding or hardcode string items in XAML...

UPDATE2:

OK I tried to make it working with MVVM:

I had to change the ObservableCollection ClassCodes
to ObservableCollection SchoolclassCodes as the Schoolclass object
has a reference to Pupil class with strings thats not possible.

Schoolclass.cs:

public string SchoolclassCode {get;set;}
...

TimeTableWeekViewModel.cs:

public ObservableCollection<Schoolclass> SchoolclassCodes
    {
        get { return _schoolclassCodes; }
        set
        {
            _schoolclassCodes = value;
            this.RaisePropertyChanged("SchoolclassCodes");
        }
    }

XAML:

How must the binding look like NOW because the SchoolclassCodes is not found by wpf ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

迷离° 2024-09-13 10:59:20

如果您正在做任何非常复杂的事情,我建议您研究 MVVM(模型-视图-视图模型)模式。此外,在模型/视图模型中实现 INotifyPropertyChanged 也很有用(例如下面示例中的 MyWeek 类)。每当您的 SchoolclassCode 属性之一发生更改时,这都会通知任何其他绑定。

以下是一些可以帮助您入门的简单示例代码:

using System.Collections.ObjectModel;
using System.Linq;

namespace BindingSample
{
    public partial class Window1
    {
        public Window1()
        {
            InitializeComponent();
            SchoolclassCodes = new ObservableCollection<string>(
                Enumerable.Range(1, 10).Select(i => "Code #" + i));
            MyWeeks = new ObservableCollection<MyWeek>(
                Enumerable.Range(1, 5).Select(i => new MyWeek() {SchoolclassCodeMonday = SchoolclassCodes.First()}));
            DataContext = this;
        }

        public ObservableCollection<string> SchoolclassCodes { get; private set; }
        public ObservableCollection<MyWeek> MyWeeks { get; private set; }
    }

    public class MyWeek
    {
        public string SchoolclassCodeMonday { get; set; }
        public string SchoolclassCodeTuesday { get; set; }
        public string SchoolclassCodeWednesday { get; set; }
        public string SchoolclassCodeThursday { get; set; }
        public string SchoolclassCodeFriday { get; set; }
        public string SchoolclassCodeSaturday { get; set; }
        public string SchoolclassCodeSunday { get; set; }
    }
}

<Window x:Class="BindingSample.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <CollectionViewSource x:Key="ClassCodes" Source="{Binding SchoolclassCodes}" />
    </Window.Resources>
    <ListView ItemsSource="{Binding MyWeeks}">
        <ListView.View>
            <GridView>
                <GridView.Columns>
                    <GridViewColumn Header="Monday">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <ComboBox SelectedValue="{Binding SchoolclassCodeMonday}"
                                          ItemsSource="{Binding Source={StaticResource ClassCodes}}"
                                          IsSynchronizedWithCurrentItem="False" />
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <!-- Other columns here... -->
                </GridView.Columns>
            </GridView>
        </ListView.View>
    </ListView>
</Window>

I recommend that you look into the MVVM (Model-View-ViewModel) pattern if you are doing anything remotely complicated. Also, it is useful to implement INotifyPropertyChanged in your model/viewmodel (e.g. the MyWeek class in my example below). That will notify any other bindings whenever one of your SchoolclassCode<Day> properties is changed.

Here is some simple sample code to get you started:

using System.Collections.ObjectModel;
using System.Linq;

namespace BindingSample
{
    public partial class Window1
    {
        public Window1()
        {
            InitializeComponent();
            SchoolclassCodes = new ObservableCollection<string>(
                Enumerable.Range(1, 10).Select(i => "Code #" + i));
            MyWeeks = new ObservableCollection<MyWeek>(
                Enumerable.Range(1, 5).Select(i => new MyWeek() {SchoolclassCodeMonday = SchoolclassCodes.First()}));
            DataContext = this;
        }

        public ObservableCollection<string> SchoolclassCodes { get; private set; }
        public ObservableCollection<MyWeek> MyWeeks { get; private set; }
    }

    public class MyWeek
    {
        public string SchoolclassCodeMonday { get; set; }
        public string SchoolclassCodeTuesday { get; set; }
        public string SchoolclassCodeWednesday { get; set; }
        public string SchoolclassCodeThursday { get; set; }
        public string SchoolclassCodeFriday { get; set; }
        public string SchoolclassCodeSaturday { get; set; }
        public string SchoolclassCodeSunday { get; set; }
    }
}

<Window x:Class="BindingSample.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <CollectionViewSource x:Key="ClassCodes" Source="{Binding SchoolclassCodes}" />
    </Window.Resources>
    <ListView ItemsSource="{Binding MyWeeks}">
        <ListView.View>
            <GridView>
                <GridView.Columns>
                    <GridViewColumn Header="Monday">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <ComboBox SelectedValue="{Binding SchoolclassCodeMonday}"
                                          ItemsSource="{Binding Source={StaticResource ClassCodes}}"
                                          IsSynchronizedWithCurrentItem="False" />
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <!-- Other columns here... -->
                </GridView.Columns>
            </GridView>
        </ListView.View>
    </ListView>
</Window>
雨轻弹 2024-09-13 10:59:20

由于列必须自动生成,因此将此代码放在适当的位置(Loaded 事件?)应该可以满足您的要求:

        ObservableCollection<String> Collection = GetCollection();

        foreach (DataGridComboBoxColumn column in DataGrid1.Columns.OfType<DataGridComboBoxColumn>())
        {
            column.ItemsSource = Collection;
        }

当然,必须应用一些修改!

Since the columns must be auto generated, putting this code in the appropriate place (Loaded event?) should do what you want :

        ObservableCollection<String> Collection = GetCollection();

        foreach (DataGridComboBoxColumn column in DataGrid1.Columns.OfType<DataGridComboBoxColumn>())
        {
            column.ItemsSource = Collection;
        }

Of course, some modifications must be applied!

不忘初心 2024-09-13 10:59:20

您不需要搞乱 DataGrid,当然也不需要创建任何具有七个不同属性的类,而您必须为其实现属性更改通知。网格控件使日历变得简单。

您的视图模型应具有三个类:MonthWeekDayWeek 类包含 Day 对象的列表,Month 类包含 Week 对象的列表。每个类都应该有一个对其父类的引用,即Day 中的WeekWeek 中的Month

Week 类的构造函数应将其 Days 属性初始化为 7 个 Day 对象的列表。 Month 类的构造函数必须具有更具体的逻辑来设置其 Weeks 属性;我会把它留给你。

Day 对象应该公开这些属性:

public DayOfWeek DayNumber { get; private set; }
public ObservableCollection<SchoolclassCode> Codes { get { return Week.Codes; } }

以及执行属性更改通知的读/写字符串 Code 属性。

Week 对象应该公开:

public ObservableCollection<SchoolclassCode> Codes { get { return Month.Codes; } }
public IEnumerable<Day> Days { get; private set; }
public IEnumerable<string> Codes
{
   get { return Days.Select(x => x.Code); }
}

然后您可以定义一个数据模板来显示天:

<DataTemplate DataType="{x:Type local:Day}">
   <Grid>
      <Grid.ColumnDefinitions>
         <ColumnDefinition SharedSizeGroup="Sunday"/>
         <ColumnDefinition SharedSizeGroup="Monday"/>
         <ColumnDefinition SharedSizeGroup="Tuesday"/>
         <ColumnDefinition SharedSizeGroup="Wednesday"/>
         <ColumnDefinition SharedSizeGroup="Thursday"/>
         <ColumnDefinition SharedSizeGroup="Friday"/>
         <ColumnDefinition SharedSizeGroup="Saturday"/>
      </Grid.ColumnDefinitions>
      <ComboBox 
         Grid.Column="{Binding DayNumber}" 
         ItemsSource="{Binding Codes}" 
         SelectedValue="{Binding Code, Mode=TwoWay}"/>
   </Grid>
</DataTemplate>

和周:

<DataTemplate DataType="{x:Type Week}">
  <ItemsControl ItemsSource="{Binding Days}">
    <ItemsControl.ItemTemplate>
      <ItemsPanelTemplate>
        <StackPanel Orientation="Horizontal"/>
      </ItemsPanelTemplate>
    </ItemsControl.ItemTemplate>
  </ItemsControl>
</DataTemplate>

以及月:

<DataTemplate DataType="{x:Type Month}">
  <ItemsControl ItemsSource="{Binding Weeks}" Grid.IsSharedSizeScope="True">
    <ItemsControl.ItemTemplate>
      <ItemsPanelTemplate>
        <StackPanel Orientation="Vertical"/>
      </ItemsPanelTemplate>
    </ItemsControl.ItemTemplate>
  </ItemsControl>
</DataTemplate>

向上述模板添加天名称和周编号非常简单。

You don't need to mess around with the DataGrid, and you certainly don't need to create any class with seven different properties that you have to implement property-change notification for. The Grid control makes calendars easy.

Your view model should have three classes: Month, Week, and Day. The Week class contains a list of Day objects, and the Month class has a list of Week objects. Each class should have a reference to its parent, i.e. Week in Day and Month in Week.

The Week class's constructor should initialize its Days property to be a list of 7 Day objects. The Month class's constructor has to have more specific logic in it for setting up its Weeks property; I'll leave that to you.

The Day object should expose these properties:

public DayOfWeek DayNumber { get; private set; }
public ObservableCollection<SchoolclassCode> Codes { get { return Week.Codes; } }

as well as a read/write string Code property that does property-change notification.

The Week object should expose:

public ObservableCollection<SchoolclassCode> Codes { get { return Month.Codes; } }
public IEnumerable<Day> Days { get; private set; }
public IEnumerable<string> Codes
{
   get { return Days.Select(x => x.Code); }
}

You can then define a data template for presenting days:

<DataTemplate DataType="{x:Type local:Day}">
   <Grid>
      <Grid.ColumnDefinitions>
         <ColumnDefinition SharedSizeGroup="Sunday"/>
         <ColumnDefinition SharedSizeGroup="Monday"/>
         <ColumnDefinition SharedSizeGroup="Tuesday"/>
         <ColumnDefinition SharedSizeGroup="Wednesday"/>
         <ColumnDefinition SharedSizeGroup="Thursday"/>
         <ColumnDefinition SharedSizeGroup="Friday"/>
         <ColumnDefinition SharedSizeGroup="Saturday"/>
      </Grid.ColumnDefinitions>
      <ComboBox 
         Grid.Column="{Binding DayNumber}" 
         ItemsSource="{Binding Codes}" 
         SelectedValue="{Binding Code, Mode=TwoWay}"/>
   </Grid>
</DataTemplate>

and weeks:

<DataTemplate DataType="{x:Type Week}">
  <ItemsControl ItemsSource="{Binding Days}">
    <ItemsControl.ItemTemplate>
      <ItemsPanelTemplate>
        <StackPanel Orientation="Horizontal"/>
      </ItemsPanelTemplate>
    </ItemsControl.ItemTemplate>
  </ItemsControl>
</DataTemplate>

and months:

<DataTemplate DataType="{x:Type Month}">
  <ItemsControl ItemsSource="{Binding Weeks}" Grid.IsSharedSizeScope="True">
    <ItemsControl.ItemTemplate>
      <ItemsPanelTemplate>
        <StackPanel Orientation="Vertical"/>
      </ItemsPanelTemplate>
    </ItemsControl.ItemTemplate>
  </ItemsControl>
</DataTemplate>

Adding day names and week numbers to the above templates is straightforward.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文