全部, Binded complete Model,值将显示在控件中,但无法让按钮单击工作...任何建议?我错过了什么或做错了什么?感谢
<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);
}
}
答案 0 :(得分:0)
您可以编写自己的命令。
这是我用于命令的基类。
它有一些非常基本的东西可以让生活更轻松。
Execute
方法接受一个对象,因此您将能够传递数组也许你想改变一些事情。我添加的所有内容都在那里,因为它非常有用。 (尤其是视图模型)
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
的{{1}},您已正确关联View
和DataContext
现在,只要单击Button,就会调用Command的Execute方法。
您的ViewModel位于View
,因此您可以轻松使用它。
在命令内或Command
内有一个按钮是非常罕见的。
关于MVVM的诀窍是将ViewModel
与View
分开并且没有
ViewModel
中的UIElements
。
如果您没有PropertyChangedBase(这个附带Caliburn.Micro),那么我建议使用一些简单的INotifyPropertyChanged实现。
I found this one here, should be german though
公共抽象类NotifyPropertyChangedBase:INotifyPropertyChanged { #region&lt; INotifyPropertyChanged&gt;成员
ViewModel
它非常易于使用!
在您的ViewModel中,您必须为Binding (这非常重要)提供公共属性,并触发更改通知。
以下是如何使用INPC的基本实现(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;
}
}
这个INPC实现为你做了NotifyOfPropertyChange调用,你不必关心它!但你必须检查最适合你情况的东西。
在您的问题中,您已经拥有ViewModelBase。也许你想用这个而不是上面的。
答案 1 :(得分:0)
请尝试用英文写作,因为我对你所写的内容感到困惑(例如“如果你在上面”,“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.");
}
}
答案 2 :(得分: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;
}
}
由于这应该为您的视图建模,您可以删除命令绑定的任何参数,并使它们成为视图模型的一部分。