wpf 无法将 MS.Internal.NamedObject 类型的对象转换为 System.Windows.Datatemplate

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20124604/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 10:05:54  来源:igfitidea点击:

Can't convert object of type MS.Internal.NamedObject to System.Windows.Datatemplate

c#wpf

提问by Robby Smet

I want to change an icon based on an enum.

我想根据枚举更改图标。

I've created a new viewmodel for my UserControl named CallControlViewModel

我为我的 UserControl 创建了一个名为 CallControlViewModel 的新视图模型

public class CallControlViewModel : BaseViewModel
{
    private InputTypeEnum _inputTypeEnum;

    public CallControlViewModel()
    {

    }

    public InputTypeEnum InputType
    {
        get { return _inputTypeEnum; }
        set
        {
            if (_inputTypeEnum != value)
            {
                _inputTypeEnum = value;
                NotifyPropertyChanged("InputType");
            }
        }
    }
}

This is the baseViewModel

这是基础视图模型

public class BaseViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// Notify of Property Changed event
    /// </summary>
    /// <param name="propertyName"></param>
    public void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }        
}

This is the enum

这是枚举

public enum InputTypeEnum
{
    Empty = 0, Number = 1, Text = 2
}

Code behind usercontrol

用户控件背后的代码

public partial class CallControl : UserControl
{
    private CallControlViewModel callControlViewModel;

    public CallControl()
    {
        InitializeComponent();
        this.Loaded += new RoutedEventHandler(CallControl_Loaded);
    }

    void CallControl_Loaded(object sender, RoutedEventArgs e)
    {
        callControlViewModel = new CallControlViewModel();
        this.DataContext = callControlViewModel;
    }

    private void CallBox_TextChanged(object sender, TextChangedEventArgs e)
    {
        InputTypeEnum type = DecideInputType();
        callControlViewModel.InputType = type;
    }

    private InputTypeEnum DecideInputType()
    {
        if(string.IsNullOrEmpty(CallBox.Text))
        {
            return InputTypeEnum.Empty;
        }

        if (IsNumeric(CallBox.Text))
        {
            return InputTypeEnum.Number;
        }

        return InputTypeEnum.Text;
    }

And this is my Xaml:

这是我的 Xaml:

<UserControl.Resources>
    <Style x:Key="InputTypeIndicatorStyle" TargetType="{x:Type ContentControl}">
    <Style.Triggers>
           <DataTrigger Binding="{Binding InputType}" Value="0">
               <Setter Property="ContentTemplate" Value="{StaticResource ResourceKey=NumberIndicator}" />
            </DataTrigger>
            <DataTrigger Binding="{Binding InputType}" Value="1">
                <Setter Property="ContentTemplate" Value="{StaticResource ResourceKey=NumberIndicator}" />
            </DataTrigger>
            <DataTrigger Binding="{Binding InputType}" Value="2">
                <Setter Property="ContentTemplate" Value="{StaticResource ResourceKey=TextIndicator}" />
             </DataTrigger>
            </Style.Triggers>
        </Style>

        <DataTemplate x:Key="NumberIndicator">
            <Border x:Name="CallIconBorder" Width="35" BorderThickness="1,0,0,0" Background="#353535" 
                    BorderBrush="#5d5d5d" MouseLeftButtonDown="CallIconBorder_MouseLeftButtonDown" Style="{StaticResource CallBorderStyle}" >
                <Image StretchDirection="DownOnly" Margin="5" Source="/Image/call.png"/>
            </Border>
        </DataTemplate>

        <DataTemplate x:Key="TextIndicator">
            <Border x:Name="SearchIconBorder" Width="35" >
                <Image StretchDirection="DownOnly" Margin="5" Source="/Image/search.png"/>
            </Border>
        </DataTemplate>
  </UserControl.Resources>

<DockPanel x:Name="CallControlDock" VerticalAlignment="Bottom" Background="{StaticResource LightGrey}" Height="30">
            <ContentControl Style="{StaticResource InputTypeIndicatorStyle}" DockPanel.Dock="Right" HorizontalAlignment="Right"  />

            <Border x:Name="ClearIconBorder" DockPanel.Dock="Right" Width="20" Visibility="Hidden" VerticalAlignment="Center" Margin="5,0,5,0" 
                    MouseDown="ClearIconBorder_MouseDown" Style="{StaticResource ClearIconStyle}" Opacity="0.5">
                <Image StretchDirection="DownOnly" Source="/Image/close.png" HorizontalAlignment="Left"/>
            </Border>

            <spinners:ucSpinnerCogs x:Name="LoadSpinner" DockPanel.Dock="Right" HorizontalAlignment="Right" Visibility="Collapsed" />

            <TextBox x:Name="CallBox" TextWrapping="Wrap" FontSize="14" FontFamily="Segoe UI Semibold" HorizontalAlignment="Stretch" 
                     Foreground="{StaticResource AlmostWhite}" VerticalAlignment="Center"  
                     GotFocus="CallBox_GotFocus" LostFocus="CallBox_LostFocus" TextChanged="CallBox_TextChanged" KeyDown="CallBox_KeyDown"
                     MouseRightButtonDown="CallBox_MouseRightButtonDown"
                     ContextMenu="{x:Null}">


            </TextBox>
        </DockPanel>

When I change the InputType property I get an error in the baseViewModel:

当我更改 InputType 属性时,我在 baseViewModel 中收到错误消息:

PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); ==>

InvalidCastException, Can't convert object of type MS.Internal.NamedObject to System.Windows.Datatemplate

InvalidCastException,无法将 MS.Internal.NamedObject 类型的对象转换为 System.Windows.Datatemplate

What am I doing wrong?

我究竟做错了什么?

回答by Sheridan

Right, this whole post is one messy red herring... for anyone not familiar with that saying, it means that you can forget all about the error given because when this is done properly, you won't get that error... it's misleading.

是的,整篇文章都是一团乱麻……对于不熟悉这句话的人来说,这意味着您可以忘记给出的所有错误,因为如果正确完成此操作,您将不会收到该错误……它是误导。

So here we go... using your Triggermethod:

所以我们开始......使用你的Trigger方法:

First, here's an enum:

首先,这是一个enum

public enum TestEnum
{
    None, One, Two, Three
}

Now the properties:

现在属性:

private TestEnum enumInstance = TestEnum.None;

public TestEnum EnumInstance
{
    get { return enumInstance; }
    set { enumInstance = value; NotifyPropertyChanged("EnumInstance"); }
}

private ObservableCollection<TestEnum> enumCollection = 
    new ObservableCollection<TestEnum>() { TestEnum.None, TestEnum.One, 
    TestEnum.Two, TestEnum.Three };

public ObservableCollection<TestEnum> EnumCollection
{
    get { return enumCollection; }
    set { enumCollection = value; NotifyPropertyChanged("EnumCollection"); }
}

Now the XAML:

现在 XAML:

<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
    <Image Width="16" Height="16" Stretch="None" Margin="0,0,0,20">
        <Image.Style>
            <Style>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding EnumInstance}" Value="One">
                        <Setter Property="Image.Source" Value="/WpfApplication2;component/Images/Copy_16.png" />
                    </DataTrigger>
                    <DataTrigger Binding="{Binding EnumInstance}" Value="Two">
                        <Setter Property="Image.Source" Value="/WpfApplication2;component/Images/Edit_16.png" />
                    </DataTrigger>
                    <DataTrigger Binding="{Binding EnumInstance}" Value="Three">
                        <Setter Property="Image.Source" Value="/WpfApplication2;component/Images/CloseRed_16.png" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Image.Style>
    </Image>
    <ComboBox ItemsSource="{Binding EnumCollection}" SelectedItem="{Binding EnumInstance}" />
</StackPanel>

I trust that you can transfer this code to your project ok. One last thing to note... if you have any more enumvalues than this, you'd be better off creating an EnumToBoolImageSourceConverterand Bindingwith that instead.

我相信您可以将此代码转移到您的项目中。最后要注意的一件事......如果你有enum比这更多的值,你最好创建一个EnumToBoolImageSourceConverterandBinding代替它。

回答by N. Kudryavtsev

For everyone who ran into the same issue but doesn't find another answers helpful in finding what exactly is going on.

对于遇到相同问题但没有找到有助于找出究竟发生了什么的其他答案的每个人。

The problem occurs when you try referencing resources with StaticResourcebeforetheir declaration.

当您尝试StaticResource声明之前引用资源时会出现问题。

In this question these resources are NumberIndicatorand TextIndicator.

在这个问题中,这些资源是NumberIndicatorTextIndicator

It is happening because StaticResourceworks at compile-time and cannot look forward. So to solve the issue you can move the resouces to where they are not referenced yet. Or just use run-time DynamicResource.

它发生是因为StaticResource在编译时工作并且无法向前看。因此,要解决该问题,您可以将资源移动到尚未引用的位置。或者只是使用运行时DynamicResource

回答by Paul Sinnema

I do remember this problem from a project some years ago. We had the same problem and added code to intercept that like so:

我确实记得几年前的一个项目中的这个问题。我们遇到了同样的问题,并添加了代码来拦截,如下所示:

    /// <summary>
    /// Tests whether the object is the 'NamedObject'. This is placed into 'DataContext' sometimes by WPF as a dummy.
    /// </summary>
    public static bool IsNamedObject(this object obj)
    {
        return obj.GetType().FullName == "MS.Internal.NamedObject";
    }

We posted several questions about this on forums but never really got an answer

我们在论坛上发布了几个关于此的问题,但从未真正得到答案