简体   繁体   中英

WPF: Reusing control with slightly different call on ViewModel?

I have a control, ActionRequiredControl.xaml that includes a combo-box with a list of enums. This control has ActionRequiredViewModel as it's DataContext, and the following call is used to populate the combobox:

    public IEnumerable<ActionType> Actions
    {
        get
        {
            return Enum.GetValues(typeof(ActionType)).Cast<ActionType>();
        }
    }

And the combo-box is as follows.

   <StackPanel Orientation="Vertical">
   <Label>Action:</Label>
   <ComboBox Width="170" MinHeight="45"  Margin="5,0,5,5" Padding="5" 
             SelectedItem="{Binding Action, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
             ItemsSource="{Binding Actions, Mode=OneTime}" 
             VerticalContentAlignment="Center" IsEnabled="{Binding IsUsed}"/>
   </StackPanel>

This control is used in two places currently (There is more to it than just the combobox) - however, I would like to re-use it in a third place, only have the "Actions" function return a different list of .

What's the best way to go about this? The only thing I can think of is creating a new class that inherits from ActionRequiredViewModel and overrides the Actions method.

最简单的解决方案是我在问题中指出的解决方案-我创建了一个继承自ActionRequiredViewModel的新类,并覆盖了“ Actions”方法以返回不同的枚举列表。

Yes, creating an additional ViewModel will be the simplest solution. I was in a similar situation some time ago, my first implementation (using MVVM light) was using two VMs, and registering both in the ViewModelLocator and providing a property for each:

SimpleIoc.Default.Register<ViewModel1>();
SimpleIoc.Default.Register<ViewModel2>();

public ViewModel ViewModel1Instance
{
    get
    {
        return ServiceLocator.Current.GetInstance<ViewModel1>();
    }
}

public ViewModel ViewModel2Instance
{
    get
    {
       return ServiceLocator.Current.GetInstance<ViewModel2>();
    }
}

And then in XAML:

<local:MyUserControl DataContext="{Binding ViewModel1Instance, 
    Source={StaticResource Locator}}" ...

However, to be a bit more flexible, I replaced this with another solution later, which provided better customization.

I played a bit with your requirements and came to this solution:

Creating a dependency property in the code behind of the user control as a proxy:

public static readonly DependencyProperty ComboBoxItemsProperty =
            DependencyProperty.Register("ComboBoxItems",
            typeof(IEnumerable<object>), typeof(TestUserControl));


public IEnumerable<object> ComboBoxItems
{
    get
    {
        return (IEnumerable<object>)GetValue(ComboBoxItemsProperty);
    }
    set
    {
        SetValue(ComboBoxItemsProperty, value);
    }
}

In the XAML of the user control:

...ItemsSource="{Binding ComboBoxItems, Mode=OneWay, RelativeSource=
    {RelativeSource AncestorType={x:Type UserControl}}}"...

In the main view model:

public IEnumerable<object> Items
{
    get
    {
        return Enum.GetValues(typeof(ActionType)).Cast<object>();
    }
 }

In the main XAML:

<local:TestUserControl ComboBoxItems="{Binding DataContext.Items, 
    Mode=OneTime, 
    RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
</local:TestUserControl>

This worked for me, but using object instead of the custom type is not the most elegant solution.

PS: This is my very first answer on SO, (and no questions yet from me...).

Since I used SO for many years as my primary source of tips and tricks, I thought I can TRY to give something back...

And of course, I admit: trying to answer is not the worst method of learning a new topic (and WPF is fairly new to me, so please don´t blame me for a suboptimal answer :-)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM