How to resolve Binding can only be set on a DependencyProperty - c#

Got a user control defined as follows:
public partial class EveBlueprintsGrid : UserControl
{
public static DependencyProperty BlueprintListProperty = DependencyProperty.Register(
"EveBlueprints",
typeof(EveBlueprintList),
typeof(EveBlueprintsGrid));
public EveBlueprintList EveBlueprints
{
get { return (EveBlueprintList)GetValue(BlueprintListProperty); }
set { SetValue(BlueprintListProperty, value); }
}
with XAML:
<DataGrid x:Name="BlueprintsDataGrid" Grid.Row="0" IsReadOnly="True" ItemsSource="{Binding Path=EveBlueprints.Blueprints, ElementName=uc}" AutoGenerateColumns="False">
With the calling XAML:
<Blueprints:EveBlueprintsGrid Grid.Column="1" EveBlueprints="{Binding Blueprints}"/>
I am getting the "A Binding can only be set on a DependencyProperty of a DependencyObject." When I look at the calling XAML.
EveBlueprints contains property Blueprints which is an ObservableCollection.
What's interesting is I have an almost exact copy of this on another object which isn't giving me the errors I'm seeing.
What am I missing here?

Related

C# WPF: Dependency Property vs MVVM

I need to create a component with Dependency Property, I don´t know how to bind the data from another user control, can someone explain it to me? I don´t think i need to create a viewmodel for the component.
Here´s my code:
Here I call the component
<DockPanel Grid.Row="1">
<ctrls:CustomComboBox Collection="{Binding Path=TestingCollection}" SelectedCollectionItem="{Binding Path=SelectedItem}"
CreateCommand="" DeleteCommand="" UpdateCommand=""/>
</DockPanel>
And Here it´s my component
<ComboBox Grid.Column="0" SelectedValue="{Binding SelectedCollectionItem,ElementName=CustomComboBoxControl, Mode=TwoWay}"
ItemsSource="{Binding Collection}"
DisplayMemberPath="Name"
SelectedValuePath="Name"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
/>
Here it is my xaml.cs
public static readonly DependencyProperty CollectionProperty =
DependencyProperty.Register("Collection", typeof(ObservableCollection<object>), typeof(CustomComboBox));
public ObservableCollection<object> Collection
{
get { return (ObservableCollection<object>)GetValue(CollectionProperty); }
set { SetValue(CollectionProperty, value); }
}
public static readonly DependencyProperty SelectedCollectionItemProperty =
DependencyProperty.Register("SelectedCollectionItem", typeof(object), typeof(CustomComboBox));
public object SelectedCollectionItem
{
get { return (object)GetValue(SelectedCollectionItemProperty); }
set { SetValue(SelectedCollectionItemProperty, value); }
}
EDIT:
I tryed creating a VM and setting the data context, and works, but dependency properties seem pointless
EDIT 2:
I succeded, i delete my VM i was lacking and ElementName in ItemSource
I succeded, i delete my VM i was lacking and ElementName in ItemSource

How to dynamically bind static DependencyProperty defined in a class to a property in another xaml class?

I have a static DependencProperty IsControlVisibleProperty in MyControl.xaml.cs. And its value is changed inside that same class. And I want to listen to this property in another control Visibility property whenever IsControlVisibleProperty value is changed.
MyControl.xaml.cs :
public partial class MyControl : UserControl
{
public static DependencyProperty IsControlVisibleProperty = DependencyProperty.Register(nameof(IsControlVisible), typeof(bool), typeof(MyControl));
public bool IsControlVisible
{
get{ return (bool)GetValue(IsControlVisibleProperty); }
set { SetValue(IsControlVisibleProperty, value); }
}
// In a function I am updating the dependency property
private void UpdateProp(bool isVisible)
{
this.SetValue(UserControl1.IsControlVisible, isVisible);
}
Now I want to use IsControlVisibleProperty value in another xaml file
SampleControl.xaml:
<UserControl x:Class="SampleControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converter="http://schemas.microsoft.com/netfx/2007/xaml/presentation"
Height="300" Width="300">
<UserControl.Resources>
<converter:BooleanToVisibilityConverter x:Key="boolToVisConverter"/>
</UserControl.Resources>
<Grid>
<local:MyControl/>
<TextBlock Name="ErrorMessage" Text="Failed to run" Visibility="{Binding ElementName="ErrorMessage" , Path=(local:MyControl.IsControlVisible), Converter={StaticResource boolToVisConverter}, Mode=TwoWay}"/>
</Grid>
So my TextBlock (ErrorMessage) is not binding the IsVisibleProperty from MyControl.xaml.cs. I want IsVisibleProperty to be always binded with TextBlock(whereever the property changes it should alse change its visibility ) not just one time on contruction . Unfortunately I am unable to achieve this . Is there any other way to do so ?
The declaration of a DependencyProperty is always static but your IsControlVisible property is not static. In fact, you can't declare a static dependency property because the GetValue and SetValue method are not static.
What you should is to define an attached dependency property in a static class:
public static class MyProperties
{
public static readonly DependencyProperty IsControlVisibleProperty = DependencyProperty.RegisterAttached(
"IsControlVisible",
typeof(bool),
typeof(MyProperties));
public static void SetIsControlVisible(UIElement element, Boolean value)
{
element.SetValue(IsControlVisibleProperty, value);
}
public static bool GetIsControlVisible(UIElement element)
{
return (bool)element.GetValue(IsControlVisibleProperty);
}
}
You can then set this property on any UIElement (or whatever the type is in your get and set accessors) using the accessors like this:
MyProperties.SetIsControlVisible(this, true); //this = the UserControl
You bind to the attached property of the parent UserControl like this:
<TextBlock Name="ErrorMessage" Text="Failed to run"
Visibility="{Binding Path=(local:MyProperties.IsControlVisible),
Converter={StaticResource boolToVisConverter},
RelativeSource={RelativeSource AncestorType=UserControl}}" />

WPF bindable dependency property is not working

I bind as follows:
views:SciChartUserControl Name="SciChartUserControl" Quotes="{Binding QuoteCollection}"></views:SciChartUserControl>
I know for sure that QuoteCollection updates because a grid also binds to it and I see it updated.I want to be notified in the code-behind of my SciChartUserControl view but QuotesPropertyChanged is never invoked. This is driving me crazy, I have tried different ways for hours...something obvious I am overlooking?
public partial class SciChartUserControl : UserControl
{
private SciChartControlViewModel _viewModel;
public SciChartUserControl()
{
//Set ViewModel Datacontext
_viewModel = new SciChartControlViewModel();
DataContext = _viewModel;
InitializeComponent();
}
public static DependencyProperty QuotesProperty = DependencyProperty.Register("Quotes", typeof(List<Quote>), typeof(SciChartUserControl), new PropertyMetadata(QuotesPropertyChanged));
public List<Quote> Quotes
{
get
{
return (List<Quote>)GetValue(QuotesProperty);
}
set
{
SetValue(QuotesProperty, value);
}
}
private static void QuotesPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
throw new NotImplementedException();
var quotes = (List<Quote>) e.NewValue;
}
}
EDIT: I added part of the view that hosts the SciChartUserControl.
<dxdo:LayoutPanel Caption="Time Series Visualization">
<views:SciChartUserControl Name="SciChartUserControl" Quotes="{Binding QuoteCollection}"></views:SciChartUserControl>
</dxdo:LayoutPanel>
<dxdo:LayoutPanel Caption="Time Series Data">
<dxg:GridControl Name="SampleDataGridControl" ItemsSource="{Binding QuoteCollection}" AutoGenerateColumns="AddNew" EnableSmartColumnsGeneration="True" AutoGeneratedColumns="SampleDataGridControl_OnAutoGeneratedColumns">
<dxg:GridControl.View>
<dxg:TableView AllowEditing="False" AutoWidth="True" BestFitArea="All" AllowBestFit="True" ShowGroupPanel="True" ShowSearchPanelMode="Always"/>
</dxg:GridControl.View>
</dxg:GridControl>
</dxdo:LayoutPanel>
Try using another constructor for the PropertyMetadata class:
public static DependencyProperty QuotesProperty = DependencyProperty.Register("Quotes",
typeof(List<Quote>), typeof(SciChartUserControl),
new PropertyMetadata(someDefaultvalue, QuotesPropertyChanged));
It could be that the single parameter constructor that takes a PropertyChangedCallback object that you are using is getting mixed up with the one that takes a single object parameter.
try this...
in the dependency property declaration change PropertyMetadata to the following..
new PropertyMetadata(null, new PropertyChangedCallback(QuotesPropertyChanged))
I believe this is because you have set your DataContext in your code behind, I ran into the same issue when setting it in XAML? It seems as though a DependencyProperty is being bound relative to the DataContext of the UserControl. UserControl's DependencyProperty is null when UserControl has a DataContext
<views:SciChartUserControl Name="SciChartUserControl"
Quotes="{Binding DataContext.QuoteCollection, RelativeSource={RelativeSource AncestorType={x:Type dxdo:LayoutPanel}}}" />

Binding not working in Windows Store App

Below is my ParamModel class which is inherited from DependencyObject
public class ParamsModel : DependencyObject
{
public object MyProperty
{
get { return (object)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(object), typeof(ParamsModel), new PropertyMetadata(null));
public ParamsModel()
{
}
}
I have referred this class in my XAML like below
<TextBox Text="{Binding DataContext.MyName,ElementName=pageRoot}" />
<ListBox ItemsSource="{Binding MyItems}"
Width="500"
Height="500">
<local:ParamsModel MyProperty="{Binding DataContext.MyName,ElementName=pageRoot}" />
</ListBox>
I have put breakpoint at MyProperty setter which is not hitting at runtime, but the same class Constructor is hitting. Could anyone please help me on this
It is because the binding mechanism don't call the CLR property of dependency property. It calls GetValue/SetValue directly.
I have been trying to bind to a DependencyObject view model in a Store App and it just wouldn't work unless I put the PropertyMetaData parameter to null instead of new PropertyMetadata(null).

Use a binding to set the text property of a textbox in a usercontrol - WPF

I have a user control which contains a textbox and have created a get/set in the usercontrol to get/set the text property of the textbox.
public class OpenFileControl : UserControl
{
StackPanel sp;
public TextBox tb;
public string Text { get { return tb.Text; } set { tb.Text = value; } }
I then want to set this value based on a binding later on -
<gX3UserControls:OpenFileControl Text="{Binding Value}" />
But I get the following exception
A 'Binding' cannot be set on the 'Text' property of type 'OpenFileControl'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.
After some investigation It seems Text needs to be a dependency property, but If I do that I cant work out how to pass the value on to the textbox.
How can I fix this.
Consider using something like this.
Control XAML:
<UserControl x:Class="WpfTestBench.OpenFileControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<TextBox Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}},
Path=Filename, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</UserControl>
Control codebehind:
using System.Windows;
namespace WpfTestBench
{
public partial class OpenFileControl
{
public static readonly DependencyProperty FilenameProperty =
DependencyProperty.Register("Filename", typeof (string), typeof (OpenFileControl));
public OpenFileControl()
{
InitializeComponent();
}
public string Filename
{
get { return (string)GetValue(FilenameProperty); }
set { SetValue(FilenameProperty, value); }
}
}
}
Main XAML:
<Window x:Class="WpfTestBench.OpenFileWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wpfTestBench="clr-namespace:WpfTestBench"
Title="OpenFileWindow" Width="300" SizeToContent="Height">
<StackPanel>
<wpfTestBench:OpenFileControl x:Name="In" Filename="{Binding SelectedFilename, UpdateSourceTrigger=PropertyChanged}" />
<wpfTestBench:OpenFileControl x:Name="Out" Filename="{Binding ElementName=In, Path=Filename}" />
</StackPanel>
</Window>
Main codebehind:
namespace WpfTestBench
{
public partial class OpenFileWindow
{
public OpenFileWindow()
{
InitializeComponent();
DataContext = this;
}
public string SelectedFilename { get; set; }
}
}
Execution result (after typing something in the first control):
If you define the dependency property as the static and the actual property, you can write whatever code behind you want in the body of the property.
public const string TextPropertyName = "Text";
public string Text
{
get
{
return (string)GetValue(TextProperty);
}
set
{
SetValue(TextProperty, value);
}
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
TextPropertyName,
typeof(string),
typeof(MyControl),
new UIPropertyMetadata(false));
In the getter and setter you can do something like textBox1.Text = value; but you'd probably be better served using a binding to the property instead. MVVM frameworks make light work of this sort of thing quite often. You might find more success defining a ViewModel (a class with an appropriate FielPath variable for example) and setting the DataContext of the new UserControl to be an instance of the ViewModel class, using Bindings to do the heavy lifting for you.

Categories