在VM中从可观察集合中的当前行设置属性

时间:2012-10-08 20:40:37

标签: c# wpf mvvm

全部 -

我正在尝试根据Observable集合中的当前项(也在VM中)设置VM中的公共属性。基本上 - 我想根据我的行将shadecolor设置为蓝色或粉红色(参见下面的示例代码)。另请参阅最终结果的图像。

有人可以建议 - 我怎么能做到这一点 - 我真的遇到了这个问题

请参阅以下示例代码:

Model.cs

public class Model
{
    public Employee empdetails { get; set; }
}

public class Employee
{
    public string fname { get; set; }
    public string lname { get; set; }
    public Enum gender { get; set; }
}

public enum gender
{
    Male,
    Female
}

ViewModel.cs

public class ViewModel
{
    public ObservableCollection<Model> employees {get; set;}
    public myCommand NextCommand { get; set; }
    private Color _shadecolor;

    public Color shadecolor
    {
        get
        {
            return _shadecolor;
        }
        set
        {
            _shadecolor = value;
        }
    }

    public ViewModel()
    {
        employees = new ObservableCollection<Model>()
        {
            #region Populating Emp 1
            new Model()
            {
                empdetails = new Employee()
                {
                    fname = "John",
                    lname = "Smith",
                    gender = gender.Male
                }
            },
            #endregion

            #region Populating Emp 2
            new Model()
            {
                empdetails = new Employee()
                {
                    fname = "Robert",
                    lname = "Ally",
                    gender = gender.Female
                }
            },
            #endregion
        };

        NextCommand = new myCommand(myNextCommandExecute, myCanNextCommandExecute);
    }

    private void myNextCommandExecute(object parameter)
    {

    }

    private bool myCanNextCommandExecute(object parameter)
    {
        return true;
    }
}

View.xaml

<Window x:Class="WpfApplication1.View"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="View" Height="500" Width="500"  WindowStyle="None" AllowsTransparency="True" Background="Transparent">
<Border VerticalAlignment="Top" HorizontalAlignment="Left" BorderBrush="Silver" BorderThickness="2" CornerRadius="15">
    <Border.Background>
        <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.511,0.957">
            <GradientStop Color="LightGray" Offset="0.55" />
            <GradientStop Color="{Binding shadecolor}" Offset="1.3" />
        </LinearGradientBrush>
    </Border.Background>
    <Grid Width="300" Height="300" Margin="3">
        <StackPanel VerticalAlignment="Top" >
            <TextBlock Text="{Binding Path=employees/empdetails.fname}" />
            <Button Command="{Binding NextCommand}" Content="Next" Width="100"></Button>
        </StackPanel>
    </Grid>
</Border>
</Window>

enter image description here

3 个答案:

答案 0 :(得分:1)

我相信你想要的是绑定SelectedItem = {Binding SelectedItem},其中Selected项也在视图模型上,公开为可观察的属性。

public Model SelectedItem
{
   ...
}

我不完全确定你在这里想要实现的是什么,因为你的XAML中没有任何东西来自Selector,因此这里没有选定项目的概念。

答案 1 :(得分:1)

为什么不使用ValueConverter?

<GradientStop Color="{Binding Path=gender, Converter={StaticResource GenderToColorConverter}" Offset="1.3" />

然后在你的价值转换器里面:

If value == Gender.Male return blue; 
return pink;

从技术上讲,我认为你会返回一个画笔,但不要引用我。

以下是一些示例代码:

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            this.DataContext = new ViewModel(GetTestEmployees());
        }

        static IEnumerable<Employee> GetTestEmployees()
        {
            return new[]
            {
                new Employee()
                {
                    FirstName = "Tom",
                    LastName = "Selleck",
                    Gender = Gender.Male
                },
                new Employee()
                {
                    FirstName = "Pat",
                    LastName = "Sajak",
                    Gender = Gender.Male,
                },
                new Employee()
                {
                    FirstName = "Mae",
                    LastName = "West",
                    Gender = Gender.Female
                }
            };
        }
    }

    public class ViewModel : INotifyPropertyChanged
    {
        public ViewModel(IEnumerable<Employee> employees)
        {
            _employees = new ObservableCollection<Employee>(employees);
            SelectedEmployee = employees.First();
        }

        ObservableCollection<Employee> _employees;
        public ObservableCollection<Employee> Employees
        {
            get { return _employees; }
        }

        Employee _selectedEmployee;
        public Employee SelectedEmployee 
        {
            get { return _selectedEmployee; }
            set
            {
                _selectedEmployee = value;
                RaisePropertyChangedEvent("SelectedEmployee");
            }
        }

        public void Next()
        {
            var curr = Employees.IndexOf(_selectedEmployee);

            if (curr == -1) throw new ArgumentOutOfRangeException();

            var next  = (curr + 1) % Employees.Count;

            SelectedEmployee = Employees[next];
        }

        ICommand _nextCommand;
        public ICommand NextCommand
        {
            get
            {
                if (_nextCommand == null)
                    _nextCommand = new NextCommand(this);

                return _nextCommand;
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void RaisePropertyChangedEvent(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public class NextCommand : ICommand
    {
        ViewModel _viewModel;

        public NextCommand(ViewModel viewModel)
        {
            _viewModel = viewModel;
        }

        public bool CanExecute(object parameter)
        {
            //throw new NotImplementedException();

            return true;
        }

        public event EventHandler CanExecuteChanged;

        public void Execute(object parameter)
        {
            //throw new NotImplementedException();

            _viewModel.Next();
        }
    }

    public class Employee
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public Gender Gender { get; set; }
    }

    public enum Gender
    {
        Male,
        Female
    }

    public class GenderToColorConverter : IValueConverter
    {

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            var gender = (Gender)value;

            if (gender == Gender.Male)
            {
                return Colors.Blue;
            }

            return Colors.Pink;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.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:loc="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <loc:GenderToColorConverter x:Key="GenderToColorConverter"/>
    </Window.Resources>
    <Grid>
        <ListBox ItemsSource="{Binding Employees}"
                      SelectedItem="{Binding SelectedEmployee}">
            <ListBox.Template>
                <ControlTemplate TargetType="ListBox">
                    <Grid>
                        <ContentControl DataContext="{TemplateBinding SelectedItem}">
                            <StackPanel >
                                <StackPanel.Background>
                                    <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.511,0.957">
                                        <GradientStop Color="LightGray" Offset="0.55" />
                                        <GradientStop Color="{Binding Path=Gender, Converter={StaticResource GenderToColorConverter}}" Offset="1.3" />
                                    </LinearGradientBrush>
                                </StackPanel.Background>
                                <TextBox Text="{Binding FirstName}"/>
                                <TextBox Text="{Binding LastName}"/>
                            </StackPanel>
                        </ContentControl>
                    </Grid>
                </ControlTemplate>
            </ListBox.Template>

        </ListBox>

        <Button VerticalAlignment="Bottom" HorizontalAlignment="Center" Content="Next" Command="{Binding NextCommand}"/>
    </Grid>
</Window>

答案 2 :(得分:0)

我能够使用Firoso提到的方法实现这个(完全可行的)解决方案(利用Josh的最佳实践,将UI逻辑保留在VM之外)。

发布完整的代码段/图片以造福他人。

模型

public class Model : CommonBase
{
    public Employee empdetails { get; set; }
}

public class Employee : CommonBase
{
    private string _fname;
    public string fname 
    {
        get
        {
            return _fname;
        }

        set
        {
            _fname = value;
            OnPropertyChanged("fname");
        }
    }
    public string lname { get; set; }
    private Enum _gender;
    public Enum gender
    {
        get
        {
            return _gender;
        }
        set
        {
            _gender = value;
            OnPropertyChanged("gender");
        }
    }
}

public enum gender
{
    Male,
    Female
}

视图模型

public class ViewModel
{
    public Model employees { get; set; }
    public myCommand NextCommand { get; set; }

    public ViewModel()
    {
        employees = new Model()
        {
            empdetails = new Employee()
            {
                fname = "John",
                lname = "Doe",
                gender = gender.Male
            }
        };

        NextCommand = new myCommand(myNextCommandExecute, myCanNextCommandExecute);
    }

    private void myNextCommandExecute(object parameter)
    {
        employees.empdetails.fname = "Ally";
        employees.empdetails.lname = "Smith";
        employees.empdetails.gender = gender.Female;
    }

    private bool myCanNextCommandExecute(object parameter)
    {
        return true;
    }
}

查看

<Window x:Class="WpfApplication1.View"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:loc="clr-namespace:WpfApplication1"
    Title="View" Height="500" Width="500"  WindowStyle="None" AllowsTransparency="True" Background="Transparent">
<Window.Resources>
    <loc:GendertoColorConverter x:Key="GendertoColorConverter"/>
</Window.Resources>
<Border VerticalAlignment="Top" HorizontalAlignment="Left" BorderBrush="Silver" BorderThickness="2" CornerRadius="15">
    <Border.Background>
        <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.511,0.957">
            <GradientStop Color="LightGray" Offset="0.55" />
            <GradientStop Color="{Binding Path=employees.empdetails.gender, Converter={StaticResource GendertoColorConverter}}" Offset="1.3" />
        </LinearGradientBrush>
    </Border.Background>
    <Grid Width="300" Height="300" Margin="3">
        <StackPanel VerticalAlignment="Top" >
            <TextBlock Text="{Binding Path=employees.empdetails.fname}" />
            <Button Command="{Binding NextCommand}" Content="Next" Width="100"></Button>
        </StackPanel>
    </Grid>
</Border>

enter image description here