Reputation: 1784
I created an user control to use it in multiple places around the app, the control have two properties, witch value are binded to the viewmodel. the problem is when the app is loading it throws an exception while setting one of the properties of the user control, any idea?
User Control.xaml
<UserControl x:Class="Client.Controls.CredentialsUserControl"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
d:DesignHeight="480" d:DesignWidth="480">
<Grid Name="LayoutRoot">
<TextBlock Text="{Binding Title}" Margin="12,20,12,390" TextWrapping="Wrap" FontSize="30"/>
<TextBlock Text="Username" Margin="39,88,260,362" FontSize="25"/>
<TextBlock Text="{Binding Credentials.User}" Margin="361,88,0,362" FontSize="25" />
<TextBlock Text="Password" Margin="39,148,260,302" FontSize="25"/>
<TextBlock Text="{Binding Credentials.Password}" Margin="361,148,0,302" FontSize="25" />
</UserControl>
UserControl.xaml.cs
public partial class CredentialUserControl: UserControl , INotifyPropertyChanged
{
public const string CredentialsPropertyName = "Credentials";
private ICredentials _credentials= null;
public ICredentials Credentials
{
get
{
_credentials_report;
}
set
{
if (_credentials== value)
{
return;
}
_credentials= value;
NotifyPropertyChanged(CredentialsPropertyName );
}
}
public string Title { get; set; }
public MobfoxReportUserControl()
{
InitializeComponent();
Loaded += PageLoaded;
}
void PageLoaded(object sender, RoutedEventArgs e)
{
this.DataContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string prop)
{
if(PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
The Usage:
<Controls:CredentialsUserControl Title="Your Credentials" Credentials="{Binding CurrentUser}"/>
The ViewModel Property snippet is the same as the showed in the UserControl.xaml.cs
The exception being thrown
System.Windows.Markup.XamlParseException occurred
Message=Set property 'CredentialsUserControl.Credentials' threw an exception. [Line: 29 Position: 85]
InnerException: System.ArgumentException
Message=ArgumentException
StackTrace:
at System.Reflection.RuntimeMethodInfo.InternalInvoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, StackCrawlMark& stackMark)
at System.Reflection.RuntimePropertyInfo.InternalSetValue(PropertyInfo thisProperty, Object obj, Object value, Object[] index, StackCrawlMark& stackMark)
at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, Object[] index)
What I found out is that the origin of the exception is the binding on the MainPage, but didn't really understand why or what is causing it.
Thanks
Upvotes: 0
Views: 1093
Reputation: 4268
You're losing the DataContext
by setting it explicitly inside your usercontrol. In addition, you should use a DependencyProperty
. Finally, your XAML is loaded with Exact margins... you might want to switch to use Grid Row/Column definitions, as if you ever need to change the page, it will be easier.
using System.Net;
using System.Windows;
using System.Windows.Controls;
namespace Client.Controls
{
public partial class CredentialsUserControl : UserControl
{
public CredentialsUserControl()
{
InitializeComponent();
if (System.ComponentModel.DesignerProperties.IsInDesignTool)
{
Credentials = new NetworkCredential("user","pass");
Title = "testing creds";
}
}
public ICredentials Credentials
{
get { return (ICredentials)GetValue(CredentialsProperty); }
set { SetValue(CredentialsProperty, value); }
}
// Using a DependencyProperty as the backing store for Credentials. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CredentialsProperty =
DependencyProperty.Register("Credentials", typeof(ICredentials), typeof(CredentialsUserControl),new PropertyMetadata(null));
public string Title { get; set; }
}
}
<Grid Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding ElementName=control, Path=Title}" TextWrapping="Wrap" FontSize="30" Margin="12,24" />
<Grid Grid.Row="1" Margin="40,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="12" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="Username" FontSize="25" Grid.Column="0" />
<TextBlock Text="{Binding ElementName=control, Path=Credentials.User}" FontSize="25" Grid.Column="1" HorizontalAlignment="Right"/>
<TextBlock Text="Password" Grid.Row="2" FontSize="25" Grid.Column="0" />
<TextBlock Text="{Binding ElementName=control, Path=Credentials.Password}" Grid.Row="2" FontSize="25" Grid.Column="1" HorizontalAlignment="Right"/>
</Grid>
</Grid>
Upvotes: 1
Reputation: 66882
I'm not sure, but what is this block of code in your constructor:
LayoutRoot.DataContext = this;
this.DataContext = this;
It looks "dangerous"...
Upvotes: 0