1

所有,绑定完整模型,值显示在控件中,但无法让按钮单击工作......有什么建议吗?我错过了什么或做错了什么?谢谢

<Window x:Class="test" Title="test" Height="350" Width="525">
    <StackPanel Name="abc" Orientation="Vertical" DataContext="{Binding Path=EMP, Mode=TwoWay}" Margin="4" Height="153">
        <Label Content="Last Name:" Margin="0,0,4,0"/>
        <TextBox Width="250" Text="{Binding Path=LastName}" Height="20"/>
        <Button Grid.Row="2" Margin="0,0,4,0" Height="40" Width="40" 
                 Command="{Binding Path=SaveCommand}" />
    </StackPanel>
</Window>

class EmployeeVM: ViewModelBase
{
    private bool _Execute = true;
    public EmployeeVM()
    {
        emp = new Model.Employee { FirstName = "abc", LastName = "xyz" };
    }
    private string sFirstName;
    private string sLastName;
    private Model.Employee emp;

    public Model.Employee EMP
    {
        get{return emp;}
        set{emp = value;
            OnPropertyChanged("EMP");}
    }
    public string LastName
    {
        get { return sLastName; }
        set 
        { 
            sLastName = value;
            OnPropertyChanged("LastName");
        }
    }

    #region Commands
    private ICommand _SaveCommand;
    public ICommand SaveCommand
    {
        get
        {
            return _SaveCommand = new CommandHandler(Save, _Execute);
        }
    }
    #endregion

    private void Save(object param)
    {
        ObservableCollection<Model.Employee> newIM = new ObservableCollection<Model.Employee>();
        foreach(Model.Employee e in newIM)
        {
            string a = e.FirstName;
            string b = e.LastName;
        }
    }
}


public class CommandHandler : ICommand
{
    Action<object> _act;
    bool _canExecute;

    public CommandHandler(Action<object> act, bool canExecute)
    {
        _act = act;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        _act(parameter);
    }
}
4

3 回答 3

0

您可以编写自己的命令。

这是我用于命令的基类。

它有一些非常基本的东西,让生活更轻松。

  • Execute方法接受一个对象,因此您将能够传递数组
  • 可以轻松传入视图模型,即您将在命令中使用的视图模型(大多数情况下,如果您不需要,请将其刷出)
  • 更改后的处理程序利用 CommandManager。这真的很有帮助

也许你想改变一些事情。我添加的所有内容都在那里,因为它非常有帮助。(尤其是视图模型)

public abstract class CommandBase : ICommand
{
    public abstract bool CanExecute(object o);
    public abstract void Execute(object o);

    public PropertyChangedBase ViewModel { get; set; }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }
}

你会有像这样的实现

public class ExampleCommand : CommandBase
{
    public ExampleCommand (PropertyChangedBase viewModel)
    {
        this.ViewModel = viewModel;
    }

    public override void Execute(object o)
    {
        // something like
        var settings = UnityContainer.Resolve<ISettings>();
        settings.MagicValue = (this.ViewModel as ConcreteViewModel).MagicValue;
    }

    public override bool CanExecute(object o)
    {
        return true;
    }
}

在您的 ViewModel 中,您通过拥有一个属性将命令公开给视图:

public class ExampleViewModel : PropertyChangedBase
{
    public ExampleViewModel ()
    {
        this.DoThisAndThatCommand = new ExampleCommand(this);
    }

    public CommandBase DoThisAndThatCommand { get; set; }
}


// and in XAML, you can use it like
<Button x:Name="Ok"
            Command="{Binding DoThisAndThatCommand }" />

(假设您已通过设置的正确连接ViewModel和)ViewDataContextView

现在,每当单击按钮时,都会调用命令的执行方法。

您的 ViewModel 就在 中Command,因此您可以轻松地使用它。

在命令或ViewModel. 关于 MVVM 的技巧是将 与View分开,ViewModel而 .UIElementsViewModel

如果您没有 PropertyChangedBase(这个是 Caliburn.Micro 附带的),那么我建议您使用一些简单的 INotifyPropertyChanged 实现。

我在这里找到了这个,不过应该是德语

公共抽象类 NotifyPropertyChangedBase : INotifyPropertyChanged { #region < INotifyPropertyChanged > 成员

    /// <summary>
    /// Is connected to a method which handle changes to a property (located in the WPF Data Binding Engine)
    /// </summary>

    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// Raise the [PropertyChanged] event
    /// </summary>
    /// <param name="propertyName">The name of the property</param>

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


    #endregion

    private Dictionary<string, object> propertyValueStorage;


    #region Constructor

    public NotifyPropertyChangedBase()
    {
        this.propertyValueStorage = new Dictionary<string, object>();
    }


    #endregion



    /// <summary>
    /// Set the value of the property and raise the [PropertyChanged] event
    /// (only if the saved value and the new value are not equal)
    /// </summary>

    /// <typeparam name="T">The property type</typeparam>
    /// <param name="property">The property as a lambda expression</param>
    /// <param name="value">The new value of the property</param>

    protected void SetValue<T>(Expression<Func<T>> property, T value)
    {
        LambdaExpression lambdaExpression = property as LambdaExpression;

        if (lambdaExpression == null)
        {
            throw new ArgumentException("Invalid lambda expression", "Lambda expression return value can't be null");
        }

        string propertyName = this.getPropertyName(lambdaExpression);

        T storedValue = this.getValue<T>(propertyName);

        if (!object.Equals(storedValue, value))
        {
            this.propertyValueStorage[propertyName] = value;

            this.OnPropertyChanged(propertyName);
        }
    }


    /// <summary> Get the value of the property </summary>
    /// <typeparam name="T">The property type</typeparam>
    /// <param name="property">The property as a lambda expression</param>
    /// <returns>The value of the given property (or the default value)</returns>
    protected T GetValue<T>(Expression<Func<T>> property)
    {
        LambdaExpression lambdaExpression = property as LambdaExpression;

        if (lambdaExpression == null)
        {
            throw new ArgumentException("Invalid lambda expression", "Lambda expression return value can't be null");
        }

        string propertyName = this.getPropertyName(lambdaExpression);
        return getValue<T>(propertyName);
    }

    /// <summary>
    /// Try to get the value from the internal dictionary of the given property name
    /// </summary>
    /// <typeparam name="T">The property type</typeparam>
    /// <param name="propertyName">The name of the property</param>
    /// <returns>Retrieve the value from the internal dictionary</returns>

    private T getValue<T>(string propertyName)
    {
        object value;

        if (propertyValueStorage.TryGetValue(propertyName, out value))
        {
            return (T)value;
        }
        else
        {
            return default(T);
        }
    }


    /// <summary>
    /// Extract the property name from a lambda expression
    /// </summary>
    /// <param name="lambdaExpression">The lambda expression with the property</param>
    /// <returns>The extracted property name</returns>
    private string getPropertyName(LambdaExpression lambdaExpression)
    {
        MemberExpression memberExpression;

        if (lambdaExpression.Body is UnaryExpression)
        {
            var unaryExpression = lambdaExpression.Body as UnaryExpression;
            memberExpression = unaryExpression.Operand as MemberExpression;
        }
        else
        {
            memberExpression = lambdaExpression.Body as MemberExpression;
        }

        return memberExpression.Member.Name;
    }
} 

这是非常容易使用!

在您的 ViewModel 中,您必须为 Binding 提供公共属性(这非常重要)并触发更改通知。

这是一个如何使用 INPC (INotifyPropertyChanged) 的基本实现的示例

public class LoginViewModel : NotifyPropertyChangedBase
{
    public string UserName { get;set; }
}

这个 INPC 实现会为您调用 NotifyOfPropertyChange,您不必关心它!但是您必须检查最适合您的情况。

在您的问题中,您已经有一个 ViewModelBase。也许您想使用这个而不是上面的。

于 2013-05-20T18:11:20.110 回答
0

请尽量用英文写,因为我对你写的东西感到困惑(例如“If uc above”、“b/c”等等:P..)

无论如何,至于您的问题,这应该可以解决:

<UserControl.Resources>
        <C:MultiValueConverter x:Key="MultiParamConverter"></C:MultiValueConverter>
    </UserControl.Resources>

    <StackPanel Orientation="Vertical">
        <StackPanel Orientation="Horizontal">
            <Button Name="Expander" Content="+" Width="25" Margin="4,0,4,0" Command="{Binding ExpanderCommand}">
                <Button.CommandParameter>
                    <MultiBinding Converter="{StaticResource MultiParamConverter}">
                        <Binding ElementName="Content"/>
                        <Binding ElementName="Expander"/>
                    </MultiBinding>
                </Button.CommandParameter>
            </Button>
            <Label FontWeight="Bold">GENERAL INFORMATION</Label>
        </StackPanel>
        <StackPanel Name="Content" Orientation="Vertical" Visibility="Collapsed">
            <Label>Test</Label>
        </StackPanel>
    </StackPanel>

命令:

public ICommand ExpanderCommand
        {
            get
            {
                return new RelayCommand(delegate(object param)
                    {
                        var args = (object[])param;
                        var content = (UIElement)args[0];
                        var button = (Button)args[1];
                        content.Visibility = (content.Visibility == Visibility.Visible) ? Visibility.Collapsed : Visibility.Visible;
                        button.Content = (content.Visibility == Visibility.Visible) ? "-" : "+";
                    });
            }
        }

和转换器:

public class MultiValueConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return values.ToArray();
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException("No two way conversion, one way binding only.");
        }
    }
于 2013-05-20T18:12:50.187 回答
0

首先,您的视图模型类应该是DependencyObject, 或实现INotifyPropertyChanged接口。您总是可以在那里找到合适的 MVVM 库并使用它们的基本视图模型类。

从您的 XAML 判断,您的 CheckBox 可以绑定到按钮的相同上下文。因此,当您将您的绑定buttonGetDetails到 中时,ClickCommand您也可以将您的绑定chkDuplicates到视图模型属性中,比如说CheckDuplicates. 因此,您不需要将其作为命令的参数,因为该属性已经在您的视图模型中。如:

class TestViewModel : ViewModelBase
{
    bool checkDuplicates;
    public bool CheckDuplicates
    {
        get { return checkDuplicates; }
        set 
        {
            if(checkDuplicates != value)
            {
                checkDuplicates = value;
                OnPropertyChanged("CheckDuplicates");
            }
         }
    }

    //Everything else is same as before
    //  except the action
    public void AnyAction(object param)
    {
        //no need for param anymore
        //var parmValues = (Object)param;
        bool test = this.CheckDuplicates;
    }        
}

由于这应该为您的视图建模,您可以摆脱命令绑定的任何参数并使它们成为您的视图模型的一部分。

于 2013-05-20T18:26:26.603 回答