WPF交互命令是指转换器的本地静态资源

时间:2017-11-21 18:50:35

标签: c# wpf xaml

我希望创建一个"可重复使用的"具有行为属性的控制项。如上所述in this blog

对于数据绑定,必须转换数据。问题是;作为StaticResource,它只能看到顶级字典(app),而动态资源不起作用("只能与依赖属性"一起使用)。 / p>

简单(工作)xaml(窗口):

<Window x:Class="testit.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Rectangle x:Name="blah" Fill="Yellow" Stroke="Black" Width="100" Height="100">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="MouseEnter" >
                    <i:InvokeCommandAction Command="{Binding MouseEnterCommand}">
                        <i:InvokeCommandAction.CommandParameter>
                            <Binding Path="Name"
                                     Converter="{StaticResource SelectionConverter}"
                                     RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=Rectangle}" />
                        </i:InvokeCommandAction.CommandParameter>
                    </i:InvokeCommandAction>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Rectangle>
        <TextBlock x:Name="namefield" Text="{Binding Data}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
    </Grid>
</Window>

应用程式:

<Application x:Class="testit.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:testit"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <local:SelectionConverter x:Key="SelectionConverter" />
    </Application.Resources>
</Application>

最后是viewmodel:

using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows.Data;

namespace testit
{
    class ViewModel : INotifyPropertyChanged
    {
        private string _data;
        private readonly DelegateCommand<string> _mouseEnterCommand = null;

        public ViewModel() {
            _data = "hello ";
            _mouseEnterCommand = new DelegateCommand<string>(
                (s) => {
                    var a = s ?? "world ";
                    Data += s;
                    return;
                });
        }

        public DelegateCommand<string> MouseEnterCommand => _mouseEnterCommand;

        public string Data {
            get { return _data; }
            set {
                if (value == _data) return;
                _data = value;
                OnPropertyChanged("Data");
            }
        }


        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName) {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    public class SelectionConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if (value == null) return "";
            char[] charArray = ((string)value).ToCharArray();
            Array.Reverse(charArray);
            return new string(charArray);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }
}

现在如上所述,这&#34;工作&#34;。然而,它并没有按照我的意愿行事:它使顶级资源字典变得混乱。我希望从app中删除该资源。并把它放在网格下面。 (或者我使用的任何面板)。

<Grid.Resources>
    <local:SelectionConverter x:Key="SelectionConverter" />
</Grid.Resources>

编辑:如果我将上面的行添加到窗口内的网格中,则编译时会抛出以下错误(行和位置参考Converter="{StaticResource SelectionConverter}"

  

&#34;&#39;为System.Windows.StaticResourceExtension&#39;提供价值。扔了一个   。例外&#39;行号&#39; 13&#39;和行位置&#39; 38&#39;。&#34;

内部异常:

  

无法找到名为&#39; SelectionConverter&#39;的资源。资源名称是   区分大小写。

为清楚起见,这是修改后的window.xaml:

<Window x:Class="testit.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        xmlns:local="clr-namespace:testit"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Rectangle x:Name="blah" Fill="Yellow" Stroke="Black" Width="100" Height="100">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="MouseEnter" >
                    <i:InvokeCommandAction Command="{Binding MouseEnterCommand}">
                        <i:InvokeCommandAction.CommandParameter>
                            <Binding Path="Name"
                                     Converter="{StaticResource SelectionConverter}"
                                     RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=Rectangle}" />
                        </i:InvokeCommandAction.CommandParameter>
                    </i:InvokeCommandAction>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Rectangle>
        <TextBlock x:Name="namefield" Text="{Binding Data}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
        <Grid.Resources>
            <local:SelectionConverter x:Key="SelectionConverter" />
        </Grid.Resources>
    </Grid>
</Window>

1 个答案:

答案 0 :(得分:2)

StaticResource标记扩展程序会在调用ProvideValue时立即解析资源:

  

Lookup behavior for that resource类似于加载时查找,它将从当前XAML页面的标记中查找以前加载的资源

如果<{1}}的内容<{1>} 之后<{1}},则Grid.Resources的内容在Grid的内容未被“先前加载”时解析。

所以把资源放在网格的顶部,所以在你使用之前定义了任何东西:

Grid

如果你能够使用<Grid> <Grid.Resources> <local:SelectionConverter x:Key="SelectionConverter" /> </Grid.Resources> <Rectangle x:Name="blah" Fill="Yellow" Stroke="Black" Width="100" Height="100"> <i:Interaction.Triggers> <i:EventTrigger EventName="MouseEnter" > <i:InvokeCommandAction Command="{Binding MouseEnterCommand}"> <i:InvokeCommandAction.CommandParameter> <Binding Path="Name" Converter="{StaticResource SelectionConverter}" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=Rectangle}" /> </i:InvokeCommandAction.CommandParameter> </i:InvokeCommandAction> </i:EventTrigger> </i:Interaction.Triggers> </Rectangle> <TextBlock x:Name="namefield" Text="{Binding Data}" HorizontalAlignment="Left" VerticalAlignment="Top"/> </Grid> ,你会没事的,但当然你不能,因为你发现的原因。