gpt4 book ai didi

wpf - WPF(MVVM)菜单中的互斥(和可绑定(bind))复选框

转载 作者:行者123 更新时间:2023-12-04 14:26:38 25 4
gpt4 key购买 nike

我试图找到一个在 WPF MVVM 应用程序的菜单中使用复选框的示例,该应用程序可以绑定(bind)到底层 ViewModel 类中的枚举。我有一个简单的例子:

public class MyViewModel
{

public MyViewModel() // constructor
{
MyChosenColor = Colors.Red; // Pick red by default...
}
public enum Colors
{
Red,
Green,
Blue, // this is just an example. Could be many more values...
}
public Colors MyChosenColor {get; set;}
}

我想要一些 XAML(如果需要,还需要最少数量的代码绑定(bind)、转换器等),允许用户选择菜单项“颜色”并查看红色、绿色、蓝色并选中红色(在开始时)。检查 Blue 会将 MyChosenColor 属性设置为 Blue 并将检查更改为 Blue。
我发现了一些有希望的链接:
Mutually exclusive checkable menu items?
How to bind RadioButtons to an enum?

但是它们似乎都没有处理所有问题(互斥复选框;复选框,而不是单选按钮),并且许多都涉及很多代码。我在 Visual Studio 2012 上,所以现在也许有更好的方法或者我忽略了一些东西?

我不得不认为绑定(bind)到枚举的菜单中互斥复选框的想法最常见。
谢谢。

最佳答案

感谢 Rachel 的评论,我在下面提出了答案。我希望它可以帮助需要这样做的人。我四处搜寻,并没有看到明确写下的示例。也许这太简单了:)我发现把所有东西都放在一起工作有点痛苦,所以我把它写在这里。再次感谢雷切尔!

<Window x:Class="Demo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Demo"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>

</Window.Resources>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="Number Of Players" ItemsSource="{Binding Path=MyCollection}">
<MenuItem.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Header" Value="{Binding Title}" />
<Setter Property="IsCheckable" Value="True" />

<Setter Property="IsChecked" Value="{Binding IsChecked,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<Setter Property="Command" Value="{Binding DataContext.MyCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MenuItem}}}" />
<Setter Property="CommandParameter" Value="{Binding Player}" />
</Style>
</MenuItem.ItemContainerStyle>


</MenuItem>

</Menu>

<Grid>

</Grid>
</DockPanel>

这是 ViewModel 代码:
namespace Demo.ViewModel
{
public class MainViewModel : ViewModelBase
{

public MainViewModel()
{
_myCollection = new ObservableCollection<NumberOfPlayersClass>();
foreach (NumberOfPlayersEnum value in Enum.GetValues(typeof(NumberOfPlayersEnum)))
{
NumberOfPlayersClass myClass = new NumberOfPlayersClass();
myClass.Player = value;
myClass.IsChecked = value == NumberOfPlayersEnum.Two ? true : false; // default to using 2 players
myClass.Title = Enum.GetName(typeof(NumberOfPlayersEnum), value);
_myCollection.Add(myClass);
}
}
private ICommand _myCommand;
public ICommand MyCommand
{
get
{
if (_myCommand == null)
{
_myCommand = new RelayCommand(new Action<object>(ResolveCheckBoxes));

}
return _myCommand;
}
}



ObservableCollection<NumberOfPlayersClass> _myCollection = new ObservableCollection<NumberOfPlayersClass>();
public ObservableCollection<NumberOfPlayersClass> MyCollection
{
get
{
return _myCollection;
}

}
public enum NumberOfPlayersEnum
{
One = 1,
Two =2,
Three =3,
}
public class NumberOfPlayersClass : ViewModelBase
{
public NumberOfPlayersClass()
{
IsChecked = false;
}
public NumberOfPlayersEnum Player { get; set; }
private bool _isChecked = false;

public bool IsChecked
{ get
{ return _isChecked;
}
set
{
_isChecked = value;
OnPropertyChanged("IsChecked");
}

}
public string Title { get; set; }

}

private void ResolveCheckBoxes(object checkBoxNumber)
{
NumberOfPlayersEnum myEnum = (NumberOfPlayersEnum)checkBoxNumber;
ObservableCollection<NumberOfPlayersClass> collection = MyCollection;
NumberOfPlayersClass theClass = collection.First<NumberOfPlayersClass>(t => t.Player == myEnum);

// ok, they want to check this one, let them and uncheck all else
foreach (NumberOfPlayersClass iter in collection)
{
iter.IsChecked = false;
}
theClass.IsChecked = true;



}
}
/// <summary>
/// A command whose sole purpose is to
/// relay its functionality to other
/// objects by invoking delegates. The
/// default return value for the CanExecute
/// method is 'true'.
/// </summary>
public class RelayCommand : ICommand
{
#region Fields

readonly Action<object> _execute;
readonly Predicate<object> _canExecute;

#endregion // Fields

#region Constructors

/// <summary>
/// Creates a new command that can always execute.
/// </summary>
/// <param name="execute">The execution logic.</param>
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}

/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");

_execute = execute;
_canExecute = canExecute;
}

#endregion // Constructors

#region ICommand Members

[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}

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

public void Execute(object parameter)
{
_execute(parameter);
}

#endregion // ICommand Members
}
}

/// <summary>
/// Base class for all ViewModel classes in the application.
/// It provides support for property change notifications
/// and has a DisplayName property. This class is abstract.
/// </summary>
public abstract class ViewModelBase : INotifyPropertyChanged, IDisposable
{
#region Constructor

protected ViewModelBase()
{
}

#endregion // Constructor

#region DisplayName

/// <summary>
/// Returns the user-friendly name of this object.
/// Child classes can set this property to a new value,
/// or override it to determine the value on-demand.
/// </summary>
public virtual string DisplayName { get; protected set; }

#endregion // DisplayName

#region Debugging Aides

/// <summary>
/// Warns the developer if this object does not have
/// a public property with the specified name. This
/// method does not exist in a Release build.
/// </summary>
[Conditional("DEBUG")]
[DebuggerStepThrough]
public void VerifyPropertyName(string propertyName)
{
// Verify that the property name matches a real,
// public, instance property on this object.
if (TypeDescriptor.GetProperties(this)[propertyName] == null)
{
string msg = "Invalid property name: " + propertyName;

if (this.ThrowOnInvalidPropertyName)
throw new Exception(msg);
else
Debug.Fail(msg);
}
}

/// <summary>
/// Returns whether an exception is thrown, or if a Debug.Fail() is used
/// when an invalid property name is passed to the VerifyPropertyName method.
/// The default value is false, but subclasses used by unit tests might
/// override this property's getter to return true.
/// </summary>
protected virtual bool ThrowOnInvalidPropertyName { get; private set; }

#endregion // Debugging Aides

#region INotifyPropertyChanged Members

/// <summary>
/// Raised when a property on this object has a new value.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;

/// <summary>
/// Raises this object's PropertyChanged event.
/// </summary>
/// <param name="propertyName">The property that has a new value.</param>
protected virtual void OnPropertyChanged(string propertyName)
{
this.VerifyPropertyName(propertyName);

PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}

#endregion // INotifyPropertyChanged Members

#region IDisposable Members

/// <summary>
/// Invoked when this object is being removed from the application
/// and will be subject to garbage collection.
/// </summary>
public void Dispose()
{
this.OnDispose();
}

/// <summary>
/// Child classes can override this method to perform
/// clean-up logic, such as removing event handlers.
/// </summary>
protected virtual void OnDispose()
{
}

#if DEBUG
/// <summary>
/// Useful for ensuring that ViewModel objects are properly garbage collected.
/// </summary>
~ViewModelBase()
{
string msg = string.Format("{0} ({1}) ({2}) Finalized", this.GetType().Name, this.DisplayName, this.GetHashCode());
System.Diagnostics.Debug.WriteLine(msg);
}
#endif

#endregion // IDisposable Members
}

您可以在 http://msdn.microsoft.com/en-us/magazine/dd419663.aspx 获取有关 RelayCommand 和 ViewModelBase 类的信息。和 http://rachel53461.wordpress.com/2011/05/08/simplemvvmexample/

关于wpf - WPF(MVVM)菜单中的互斥(和可绑定(bind))复选框,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16009159/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com