Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何将视图控件正确绑定到ViewModel列表(WPF MVVM)_C#_Wpf_Xaml_Mvvm - Fatal编程技术网

C# 如何将视图控件正确绑定到ViewModel列表(WPF MVVM)

C# 如何将视图控件正确绑定到ViewModel列表(WPF MVVM),c#,wpf,xaml,mvvm,C#,Wpf,Xaml,Mvvm,我需要使用WPF MVVM将一个列表绑定到一个UniformGrid到一个WP窗口中 我想这样做: 进入我的虚拟机: private List<Rat> rats; private UniformGrid uniformGrid; public List<Rat> Rats { get { return rats; } set {

我需要使用WPF MVVM将一个列表绑定到一个UniformGrid到一个WP窗口中

我想这样做:

进入我的虚拟机:

   private List<Rat> rats;
        private UniformGrid uniformGrid;
        public List<Rat> Rats
        {
            get { return rats; }
            set
            {

                if (rats != value)
                    {
                    //update local list value
                        rats = value;

                    //create View UniformGrid
                        if (uniformGrid == null)
                            uniformGrid = new UniformGrid() { Rows=10};
                        else
                            uniformGrid.Children.Clear();
                    foreach(Rat rat in value)
                    {
                        StackPanel stackPanel = new StackPanel();
                        Ellipse ellipse = new Ellipse(){Height=20, Width=20, Stroke= Brushes.Black};
                        if (rat.Sex== SexEnum.Female)
                            ellipse.Fill= Brushes.Pink;
                        else 
                             ellipse.Fill= Brushes.Blue;

                        stackPanel.Children.Add(ellipse  );
                        TextBlock textBlock = new TextBlock();
                        textBlock.Text= rat.Name + " (" + rat.Age +")";
                        stackPanel.Children.Add( textBlock  );
                        uniformGrid.Children.Add(stackPanel);
                    }


                        OnPropertyChanged("Rats");
                    }            
            }
        }
->

这让我认为,我不应该从MVVM的角度来处理这个问题


谢谢您的帮助。

视图模型不应该实例化任何UI控件,这应该是视图的责任

因此,在代码中不应尝试创建
StackPanels
省略号

同时尝试使用已经有更改通知的类型-for,而不是
List
使用
ObservableCollection
,我不建议在其值更改时替换整个列表

在MVVM模式中执行此操作的正确方法是为
Rat
创建一个
DataTemplate
,如下所示:

视图模型:

public class MainWindowViewModel
{
    public ObservableCollection<Rat> Rats { get; set; } =
        new ObservableCollection<Rat>()
        {
            new Rat()
            {
                Name = "Fred",
                Age = "19",
                Sex = SexEnum.Male
            },
            new Rat()
            {
                Name = "Martha",
                Age = "21",
                Sex = SexEnum.Female
            }
        };

}
当你想用两种颜色中的一种呈现性别的模型值时,你应该使用
IValueConverter

[ValueConversion(typeof(SexEnum), typeof(Brush))]
public class SexToColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (!(value is SexEnum))
            throw new ArgumentException("value not of type StateValue");
        SexEnum sv = (SexEnum)value;
        //sanity checks
        if (sv == SexEnum.Female)
            return Brushes.Red;
        return Brushes.Blue;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
然后在您的窗口中使用:

窗口:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525"
        xmlns:ViewModel="WpfApplication1.VM"
        xmlns:Converters ="clr-namespace:WpfApplication1.Converters"
        >
    <Grid>
        <Grid.Resources>
            <Converters:SexToColorConverter x:Key="SexToBrushConverter"></Converters:SexToColorConverter>
        </Grid.Resources>
        <ComboBox x:Name="comboBox" ItemsSource="{Binding Rats}" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="120">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Ellipse Width="10" Height="10" Fill="{Binding Sex, Converter={StaticResource SexToBrushConverter}}"></Ellipse>
                        <TextBlock Margin="5" Text="{Binding Name}"></TextBlock>
                        <TextBlock Margin="5" Text="{Binding Age}"></TextBlock>
                    </StackPanel>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>

    </Grid>
</Window>

我猜目标也是选择RAT,这取决于您希望成为的MVVM纯粹主义者,您需要添加一个
RatViewModels
列表,具有bool IsChecked属性并将
项资源
绑定到
可观察集合
,并将此列表与您的模型同步
列表

视图模型
不应实例化任何UI控件,这应该是视图的责任

因此,在代码中不应尝试创建
StackPanels
省略号

同时尝试使用已经有更改通知的类型-for,而不是
List
使用
ObservableCollection
,我不建议在其值更改时替换整个列表

在MVVM模式中执行此操作的正确方法是为
Rat
创建一个
DataTemplate
,如下所示:

视图模型:

public class MainWindowViewModel
{
    public ObservableCollection<Rat> Rats { get; set; } =
        new ObservableCollection<Rat>()
        {
            new Rat()
            {
                Name = "Fred",
                Age = "19",
                Sex = SexEnum.Male
            },
            new Rat()
            {
                Name = "Martha",
                Age = "21",
                Sex = SexEnum.Female
            }
        };

}
当你想用两种颜色中的一种呈现性别的模型值时,你应该使用
IValueConverter

[ValueConversion(typeof(SexEnum), typeof(Brush))]
public class SexToColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (!(value is SexEnum))
            throw new ArgumentException("value not of type StateValue");
        SexEnum sv = (SexEnum)value;
        //sanity checks
        if (sv == SexEnum.Female)
            return Brushes.Red;
        return Brushes.Blue;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
然后在您的窗口中使用:

窗口:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525"
        xmlns:ViewModel="WpfApplication1.VM"
        xmlns:Converters ="clr-namespace:WpfApplication1.Converters"
        >
    <Grid>
        <Grid.Resources>
            <Converters:SexToColorConverter x:Key="SexToBrushConverter"></Converters:SexToColorConverter>
        </Grid.Resources>
        <ComboBox x:Name="comboBox" ItemsSource="{Binding Rats}" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="120">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Ellipse Width="10" Height="10" Fill="{Binding Sex, Converter={StaticResource SexToBrushConverter}}"></Ellipse>
                        <TextBlock Margin="5" Text="{Binding Name}"></TextBlock>
                        <TextBlock Margin="5" Text="{Binding Age}"></TextBlock>
                    </StackPanel>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>

    </Grid>
</Window>

我猜目标也是选择老鼠,这取决于你想成为MVVM纯粹主义者的方式。你应该添加一个具有bool-IsChecked属性的
RatViewModels
列表,并将
ItemsSource
绑定到
observedcollection
并将该列表与你的模型
List

精彩答案同步。非常感谢。在我结束这个问题之前,你知道如何坚持使用Groupbox而不是切换到ComboBox或ListBox吗?我需要使用GroupBox来保留应用程序的设计。但是GroupBox没有任何ItemsSource属性,而不是UniformGrid。很抱歉,错过了
GroupBox
-
GroupBox
只是一个容器,并不真正用于绑定,您应该将自定义数量的项绑定到
ItemControl
,例如
组合框
。在这里,您必须编辑模板以包含复选框。你在那里追求的目标是什么?你需要在事后得到选中的老鼠吗?它就像一个符咒,谢谢你的帮助。我赢得了很多时间!精彩的回答。非常感谢。在我结束这个问题之前,你知道如何坚持使用Groupbox而不是切换到ComboBox或ListBox吗?我需要使用GroupBox来保留应用程序的设计。但是GroupBox没有任何ItemsSource属性,而不是UniformGrid。很抱歉,错过了
GroupBox
-
GroupBox
只是一个容器,并不真正用于绑定,您应该将自定义数量的项绑定到
ItemControl
,例如
组合框
。在这里,您必须编辑模板以包含复选框。你在那里追求的目标是什么?你需要在事后得到选中的老鼠吗?它就像一个符咒,谢谢你的帮助。我赢得了很多时间!
<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525"
        xmlns:ViewModel="WpfApplication1.VM"
        xmlns:Converters ="clr-namespace:WpfApplication1.Converters"
        >
    <Grid>
        <Grid.Resources>
            <Converters:SexToColorConverter x:Key="SexToBrushConverter"></Converters:SexToColorConverter>
        </Grid.Resources>
        <ComboBox x:Name="comboBox" ItemsSource="{Binding Rats}" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="120">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Ellipse Width="10" Height="10" Fill="{Binding Sex, Converter={StaticResource SexToBrushConverter}}"></Ellipse>
                        <TextBlock Margin="5" Text="{Binding Name}"></TextBlock>
                        <TextBlock Margin="5" Text="{Binding Age}"></TextBlock>
                    </StackPanel>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>

    </Grid>
</Window>
<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525"
        xmlns:Converters ="clr-namespace:WpfApplication1.Converters"
        xmlns:vm="clr-namespace:WpfApplication1.VM">
    <Window.DataContext>
        <vm:MainWindowViewModel/>
    </Window.DataContext>
    <Grid>
        <Grid.Resources>
            <Converters:SexToColorConverter x:Key="SexToBrushConverter"></Converters:SexToColorConverter>
        </Grid.Resources>
        <GroupBox>
            <ItemsControl ItemsSource="{Binding Rats}" >
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <CheckBox Margin="5"></CheckBox>
                            <Ellipse Width="10" Height="10" Fill="{Binding Sex, Converter={StaticResource SexToBrushConverter}}"></Ellipse>
                            <TextBlock Margin="5" Text="{Binding Name}"></TextBlock>
                            <TextBlock Margin="5" Text="{Binding Age}"></TextBlock>
                        </StackPanel>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </GroupBox>
    </Grid>
</Window>