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 m开发者_如何学Pythonake 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 ?
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>
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!
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.
精彩评论