将 RoutedEvent 或 RoutedCommand 冒泡到 ViewModel

发布于 2024-08-02 00:47:52 字数 1263 浏览 5 评论 0原文

我有一个 ViewModel 集合,它们使用某种样式呈现为选项卡,以提取要在选项卡上显示的相关内容:

public class TabViewModel : DependencyObject
{
      public object Content
      {
          get { return (object)GetValue(ContentProperty); }
          set
          {
              SetValue(ContentProperty, value);
          }
      }

}

这是 TabControl:

<TabControl 
     ItemsSource={Binding MyCollectionOfTabViewModels}" 
     ItemContainerStyle="{StaticResource TabItemStyle}" />

这是样式

<Style TargetType="TabItem" x:Key="TabItemStyle">
     <Setter Property="Content" Value="{Binding Content}"/>
</Style>

我们正在创建用户控件的实例并设置“内容” TabViewModel 的属性更改为该值,以便用户控件显示在 TabItem 的内容区域中。

MyCollectionOfViewModels.Add(new TabViewModel() 
{ 
     Content = new MyUserControl();
});

我的问题是,我希望允许添加到 TabViewModel 的 Content 属性的 MyUserControl(或其任何子控件)引发 TabViewModel 处理的事件

有人知道我会怎么做吗?

我们已经尝试使用 RoutedEvents 和 RoutedCommands,但无法让任何东西 100% 工作并与 MVVM 兼容。 我真的认为这可以通过 RoutedEvent 或 RoutedCommand 来完成,但我似乎无法让它发挥作用。

注意:我已经删除了一些相关的 Prism 特定代码,但如果您想知道为什么我们会做如此愚蠢的事情,那是因为我们试图通过使用 Prism 的 RegionManager 来保持控制不可知性。

I've got a collection of ViewModels that are rendered as tabs using a style to pull out the relevant content to display on the tab:

public class TabViewModel : DependencyObject
{
      public object Content
      {
          get { return (object)GetValue(ContentProperty); }
          set
          {
              SetValue(ContentProperty, value);
          }
      }

}

Here's the TabControl:

<TabControl 
     ItemsSource={Binding MyCollectionOfTabViewModels}" 
     ItemContainerStyle="{StaticResource TabItemStyle}" />

And here's the style

<Style TargetType="TabItem" x:Key="TabItemStyle">
     <Setter Property="Content" Value="{Binding Content}"/>
</Style>

We are creating an instance of a usercontrol and setting the "Content" property of the TabViewModel to that so that the usercontrol gets displayed in the TabItem's Content area.

MyCollectionOfViewModels.Add(new TabViewModel() 
{ 
     Content = new MyUserControl();
});

My question is, I would like to allow a MyUserControl (or any of its sub controls) added to the TabViewModel's Content property to be allowed to raise an event that the TabViewModel handles.

Anyone know how I would do that?

We've experimented using RoutedEvents and RoutedCommands, but haven't been able to get anything to work 100% and have it be compatible with MVVM. I really think that this could be done with a RoutedEvent or RoutedCommand, but I don't seem to be able to get this to work.

Note: I've removed some of the relevant Prism-specific code, but if you are wondering why we do something so silly, it is because we are trying to stay control agnostic by using Prism's RegionManager.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

洒一地阳光 2024-08-09 00:47:52

您可以将 State 属性添加到 TabViewModel 中,并检查 DependencyPropertyChanged 事件。

因此,想象一下以下枚举:

public enum TabViewModelState
{
    True,
    False,
    FileNotFound
}

然后将一个 State 属性添加到该枚举的 TabViewModel 中:

public static readonly DependencyProperty StateProperty =
    DependencyProperty.Register("State", typeof(TabViewModelState), typeof(TabViewModel), new PropertyMetadata(OnStateChanged));

private static void OnStateChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    TabViewModel viewModel= (TabViewModel)obj;

    //Do stuff with your viewModel
}

在控件中使用对此属性的双向绑定:

<CheckBox Checked="{Binding Path=State, Converter={StaticResource StateToBooleanConverter}, Mode=TwoWay}" />

最后但并非最不重要的是实现转换器,该转换器将在所需的原始值之间进行转换控件..(在我的示例中,布尔<--> TabViewModelState):

public class StateToBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        TabViewModelState state = (TabViewModelState) value;
        return state == TabViewModelState.True;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool result = (bool) value;
        return result ? TabViewModelState.True : TabViewModelState.False;
    }
}

现在您有一个由UI管理的State属性,并在需要响应时抛出更改的事件..

希望这有帮助!

You could add a State property to your TabViewModel, and check the DependencyPropertyChanged events.

So imagine the following enum:

public enum TabViewModelState
{
    True,
    False,
    FileNotFound
}

Then add a State property to your TabViewModel of this enum:

public static readonly DependencyProperty StateProperty =
    DependencyProperty.Register("State", typeof(TabViewModelState), typeof(TabViewModel), new PropertyMetadata(OnStateChanged));

private static void OnStateChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    TabViewModel viewModel= (TabViewModel)obj;

    //Do stuff with your viewModel
}

Use a two-way binding to this property in your control:

<CheckBox Checked="{Binding Path=State, Converter={StaticResource StateToBooleanConverter}, Mode=TwoWay}" />

And last but not least implement the converter that will convert to and from the original value needed for the control.. (in my example boolean <--> TabViewModelState):

public class StateToBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        TabViewModelState state = (TabViewModelState) value;
        return state == TabViewModelState.True;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool result = (bool) value;
        return result ? TabViewModelState.True : TabViewModelState.False;
    }
}

So now you have a State property that is managed by the UI, and throws changed events when you need to respond..

Hope this helps!

半城柳色半声笛 2024-08-09 00:47:52

如果您在 ViewModel 上放置一个命令并从 UserControl 绑定到该命令,它无论如何都会触发。 您不必冒泡它,用户控件只会找到命令并使用它。

如果您的 ViewModel 上有一个委托命令“GoCommand”,您的 UserControls 按钮绑定将如下所示:

<Button Command="{Binding GoCommand}" >Go</Button>

我经历了相同的思维过程,认为 UserControl 需要冒泡命令,但事实并非如此 - 绑定只会当它在 ViewModel 上找到该命令时,它会自行挂接。

希望这有帮助,我没有错过重点! ;)

If you put a command on your ViewModel and just bind to that from your UserControl it will fire anyway. You don't have to bubble it, the UserControl will just find the command and use it.

If you had a delegate command 'GoCommand' on your ViewModel, your UserControls button binding would just look like this:

<Button Command="{Binding GoCommand}" >Go</Button>

I went through the same thought process thinking that the UserControl needs to bubble the command, but it dosn't - the binding will just hook itself up when it finds the command on the ViewModel.

Hope this helps and I havn't missed the point! ;)

烦人精 2024-08-09 00:47:52

You should have a look at Marlon Grech's Attached Command Behavior, which allows you to attach a ViewModel command to an GUI event.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文