Search code examples
c#xamluwpicommand

UWP ICommand DependencyProperty cast error


I have a problem with binding an DependencyProperty of type ICommand. This is my custom user control:

<UserControl x:Class="HexEditor.Controls.NavButton"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="using:HexEditor.Controls"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             d:DesignHeight="300"
             d:DesignWidth="400"
             DataContext="{Binding RelativeSource={RelativeSource Self}}"
             mc:Ignorable="d">

    <ToggleButton x:Name="toggleWrap"
                  Width="140"
                  Height="48"
                  Background="Transparent"
                  BorderThickness="0"
                  Command="{Binding Command}"
                  CommandParameter="{Binding CommandParameter}"
                  IsChecked="{Binding IsChecked}">
        <Grid Width="140">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <FontIcon Margin="6,0,0,0"
                      Glyph="{Binding Icon}" />
            <TextBlock Grid.Column="1"
                       Margin="32,0,0,0"
                       Text="{Binding Title}" />
        </Grid>
    </ToggleButton>
</UserControl>

This is code behind of my control:

public sealed partial class NavButton : UserControl
    {
        public NavButton()
        {
            this.InitializeComponent();
        }

        public static readonly DependencyProperty IconProperty =
            DependencyProperty.Register("Icon", typeof(string), typeof(FontIcon), new PropertyMetadata(""));

        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.Register("Title", typeof(string), typeof(TextBlock), new PropertyMetadata(""));

        public static readonly DependencyProperty IsCheckedProperty =
            DependencyProperty.Register("IsChecked", typeof(bool), typeof(ToggleButton), new PropertyMetadata(""));

        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.Register("Command", typeof(ICommand), typeof(ToggleButton), new PropertyMetadata(""));

        public static readonly DependencyProperty CommandParameterProperty =
            DependencyProperty.Register("CommandParameter", typeof(object), typeof(ToggleButton), new PropertyMetadata(""));

        public string Icon
        {
            get { return (string)GetValue(IconProperty); }
            set { SetValue(IconProperty, value); }
        }

        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        public bool IsChecked
        {
            get { return Convert.ToBoolean(GetValue(IsCheckedProperty)); }
            set { SetValue(IsCheckedProperty, value); }
        }

        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }

        public object CommandParameter
        {
            get { return GetValue(CommandParameterProperty); }
            set { SetValue(CommandParameterProperty, value); }
        }
    }

And this is a page where i use my control:

<UserControl x:Class="HexEditor.Common.RootFrame"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:Controls="using:HexEditor.Controls"
             xmlns:Interactions="using:Microsoft.Xaml.Interactions.Core"
             xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="using:HexEditor.Common"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             d:DesignHeight="300"
             d:DesignWidth="400"
             DataContext="{Binding CommonViewModel,
                                   Source={StaticResource Locator}}"
             mc:Ignorable="d">
    <Grid Background="White">
        <SplitView x:Name="navSplitView"
                   Width="Auto"
                   DisplayMode="CompactOverlay"
                   OpenPaneLength="140">
            <SplitView.Pane>
                <StackPanel>
                    <ToggleButton x:Name="hamBtn"
                                  Width="48"
                                  Height="48"
                                  BorderThickness="0">
                        <FontIcon Glyph="&#xE700;" />
                    </ToggleButton>
                    <Controls:NavButton Title="Home"
                                        Command="{Binding NavigationCommand}"
                                        CommandParameter="HomePage"
                                        Icon="&#59407;"
                                        IsChecked="True" />
                    <Controls:NavButton Title="Settings"
                                        Command="{Binding NavigationCommand}"
                                        CommandParameter="SettingsPage"
                                        Icon="&#59155;"
                                        IsChecked="False" />
                </StackPanel>
            </SplitView.Pane>
            <SplitView.Content>
                <Frame x:Name="NavFrame" />
            </SplitView.Content>
            <Interactivity:Interaction.Behaviors>
                <Interactions:DataTriggerBehavior Binding="{Binding IsChecked,
                                                                    ElementName=hamBtn}"
                                                  Value="True">
                    <Interactions:ChangePropertyAction PropertyName="IsPaneOpen"
                                                       TargetObject="{Binding ElementName=navSplitView}"
                                                       Value="True" />
                </Interactions:DataTriggerBehavior>
                <Interactions:DataTriggerBehavior Binding="{Binding IsChecked,
                                                                    ElementName=hamBtn}"
                                                  Value="False">
                    <Interactions:ChangePropertyAction PropertyName="IsPaneOpen"
                                                       TargetObject="{Binding ElementName=navSplitView}"
                                                       Value="False" />
                </Interactions:DataTriggerBehavior>
            </Interactivity:Interaction.Behaviors>
        </SplitView>
    </Grid>

</UserControl>

Here's the ViewModel:

public class CommonViewModel : ViewModelBase
    {
        public CommonViewModel()
        {
            this.NavigationCommand = new RelayCommand<NavigationSource>(this.ExecuteNavigationCommand);
        }

        public ICommand NavigationCommand { get; private set; }

        private void ExecuteNavigationCommand(NavigationSource state)
        {
            NavigationProvider.Instance.NavigateTo(state);
        }
    }

When compiling, exception appears:

Exception thrown: 'System.InvalidCastException' in HexEditor.exe
'HexEditor.exe' (CoreCLR: CoreCLR_UWP_Domain): Loaded 'C:\Users\Root\documents\visual studio 2015\Projects\HexEditor\HexEditor\bin\x86\Debug\AppX\System.Resources.ResourceManager.dll'. Module was built without symbols.
Exception thrown: 'Windows.UI.Xaml.Markup.XamlParseException' in HexEditor.exe
WinRT information: Failed to assign to property 'HexEditor.Controls.NavButton.Command'. [Line: 29 Position: 41]
An exception of type 'Windows.UI.Xaml.Markup.XamlParseException' occurred in HexEditor.exe but was not handled in user code
WinRT information: Failed to assign to property 'HexEditor.Controls.NavButton.Command'. [Line: 29 Position: 41]
Additional information: The text associated with this error code could not be found.

Failed to assign to property 'HexEditor.Controls.NavButton.Command'. [Line: 29 Position: 41]

What i'm doing wrong?


Solution

  • I think the problem is that you have default values of "" for dependency properties of type bool and ICommand (new PropertyMetadata("") in both cases). You can't cast a string to either one, and that will cause an exception to be thrown. IsChecked should default to false, and Command should default to null.

    This may or may not be relevant to the exact issue you're asking about, but it matters too: The third parameter of DependencyProperty.Register() should be the type of the owning class. That's typeof(NavButton) in your case, for all of its dependency properties.