Custom functionality of inner components on setting userControl "isEnabled" - c#

I've created a silverlight UserControl with some inner elements that I'd like to custom change when the controls isEnabled property is set (for example changing some inner Image controls to look greyed out). With other properties I set up a DependencyProperty and do the code there, but this doesn't called for isEnabled (I assume because it's already declared). The code is below;
public static readonly DependencyProperty EnabledProperty =
DependencyProperty.Register("isEnabled", typeof(bool), typeof(BreadcrumbElement), null);
public bool isEnabled
{
get { return (bool)GetValue(TitleProperty); }
set
{
SetValue(TitleProperty, value);
if (value)
Chevron.Source = new BitmapImage(new Uri("../Resources/ChevronRight.png", UriKind.Relative));
else
Chevron.Source = new BitmapImage(new Uri("../Resources/ChevronRight_Disabled.png", UriKind.Relative));
}
}
I'd like to use isEnabled instead of something else, so is there a way to get this to function correctly? Thanks :)

Hook onto Control.IsEnabledChanged Event and write your code in the handler of this event
http://msdn.microsoft.com/en-us/library/system.windows.controls.control.isenabledchanged%28v=vs.95%29.aspx

Related

Binding A UserControl DependencyProperty, Always DefaultValue?

I've got a UserControl with a DependencyProperty created in its CodeBehind:
public partial class PanelMap_Control : UserControl
{
public ObservableCollection<GMapMarker> Markers
{
get { return (ObservableCollection<GMapMarker>)GetValue(MarkersProperty); }
set { SetValue(MarkersProperty, value); }
}
public static readonly DependencyProperty MarkersProperty = DependencyProperty.Register("Markers", typeof(ObservableCollection<GMapMarker>), typeof(PanelMap_Control), new PropertyMetadata(null));
}
Inside the UserControl is a Map, which contains the original collection of markers (not a DependencyProperty). I need to make this available for binding outside the UserControl, so at the end of the constructor (once the map's Markers are all setup), I set it to the control's DependencyProperty:
public PanelMap_Control()
{
InitializeComponent();
//...map setup...
this.Markers = _map.Markers;
}
Then, users of the UserControl can bind like:
<local:PanelMap_Control Markers="{Binding Path=MapMarkers, Mode=OneWayToSource}"/>
Where in the ViewModel:
public ObservableCollection<GMap.NET.WindowsPresentation.GMapMarker> MapMarkers
{
private get
{
return _mapMarkers;
}
set
{
_mapMarkers = value;
}
}
private ObservableCollection<GMap.NET.WindowsPresentation.GMapMarker> _mapMarkers;
The problem is, the ViewModel's MapMarkers property always ends up with the default value "null." I tried setting breakpoints on the SetValue call in PanelMap_Control and the ViewModel property's setter. The debugger first hits SetValue(), at which point _map.Markers is valid (non-null). THEN it hits the ViewModel's setter, with a value of null - and never reflects the actual valid object I pass to SetValue().
I'm sure I'm just missing something simple, but I can't for the life of me figure out why SetValue(non-null) would be followed by ViewModel.MapMarkers.set(null)...and never again.
(Side note 1: I realize this DependencyProperty won't work for TwoWay binding - i.e. I can't update _map.Markers in the UserControl. That's fine, I only need to read from it externally.)
(Side note 2: The _map.Markers object will never be changed - only the items in the collection - so setting the DependencyProperty to the initial collection should be sufficient.)
Please refer to the following questions.
OneWayToSource Binding seems broken in .NET 4.0
OneWayToSource binding resetting target value
OneWayToSource does actually reset the target property (Markers) initially. This is by design. There is more information about this on the links above.
As a workaround you could try to set up the binding programmatically:
public MainWindow()
{
InitializeComponent();
var vm = new ViewModel();
DataContext = vm;
vm.MapMarkers = control.Markers;
BindingOperations.SetBinding(control, PanelMap_Control.MarkersProperty, new Binding("MapMarkets") { TargetNullValue = control.Markers, FallbackValue = control.Markers });
}
XAML:
<local:PanelMap_Control x:Name="control" />

Bind control to another property

My boss had downloaded a xaml control that I must use in app. It looks like ok but there is a strange trouble with inner logic - the
property CurrentColor (that I need to use in our app) is defined in control.xaml.cs file like :
public SolidColorBrush CurrentColor
{
get { return (SolidColorBrush)GetValue(CurrentColorProperty); }
set
{
SetValue(CurrentColorProperty, value);
ActiveColor = CurrentColor;
}
}
I am using this control in my dialog (that has its own view model class) and
I am writing this kind of binding:
CurrentColor="{Binding myOwnViewModel.ColorActualValue, Mode=Default, UpdateSourceTrigger=PropertyChanged}">
in myOwnViewModel.cs (that implements INotifyPropertyChanged) I have my property
public SolidColorBrush ColorActualValue{ // here is some logic}
But when I debug an app I have never target MY CurrentColor - I am always go to the CurrentColor from control.xaml.cs
How could I bind this "third party" control to my property from my ViewModel?
Perhaps this is because (control.xaml.cs):
public static DependencyProperty CurrentColorProperty =
DependencyProperty.Register("CurrentColor", typeof(SolidColorBrush), typeof(ColorPickerComboBox), new PropertyMetadata(Brushes.Chocolate));
public static RoutedEvent ActiveColorChangedEvent = EventManager.RegisterRoutedEvent("ActiveColorChanged",
RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ColorPickerComboBox));
I have found the question What's wrong with "DataContext = this" in WPF user controls? and removed DataContext = this; from constructor of this control - but this still not helped
Should the binding look like this?
CurrentColor="{Binding ColorActualValue, Mode=Default, UpdateSourceTrigger=PropertyChanged}">
The DataContext of your 'dialog' needs to be the ViewModel class that contains the ColorActualValue property
public Dialog()
{
DataContext = new myOwnViewModel();
}

Binding - callback is called twice

I've a simple control with dependency property like this
public class StatusProgress : Control
{
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(StatusProgress),
new FrameworkPropertyMetadata(null, (d, e) => (d as StatusProgress).TextUpdated(e.OldValue as string)));
private void TextUpdated(string text)
{
Trace.WriteLine("test");
}
}
then I have view model
public class ViewModelPageAnalyse : ViewModelPageBase
{
private string _progressText;
public string ProgressText
{
get { return _progressText; }
set
{
_progressText = value;
OnPropertyChanged(); // base class INotifyPropertyChanged implementation
}
}
}
Then there is a user control (displayed in window with ContentControl). User control is bound to view model with data template (maybe this is important)
<DataTemplate DataType="{x:Type local:ViewModelPageAnalyse}">
<local:UserControlAnalyse/>
</DataTemplate>
And this is the control in user control
<local:StatusProgress Text="{Binding ProgressText}"/>
Now the interesting part. When ProgressText in view model is set/changed, property changed callback is called twice. I see twice "test" in the debugger output window.
More interesting: when view is changed, for some reason callback is again called with e.NewValue = null, while there is nothing directly sets ProgressText to null.
I tried already to check if value is changed in the ProgressText setter before rising event, tried to set binding mode one-way, problem still - callback is called twice with same value, call stack looks same, but there are really a lot of calls within wpf to be really sure.
While double-shot is not a real issue, it bother me. Callback with null value is what my real problem (I think they are related). Anyone knows what is wrong?
Found a reason of the first problem: it was other control with Content. During transition it created a new Model (because Content is ViewModel) instead of reassigning existing user control. Totally my fault. Second problem still and I found this question (with workaround which is not suiting me).
Need help with
PropertyChanged callback is called with default value when ContentControl ViewModel is changed.
Which means null for Text in my case. Anyone? I couldn't figure out why is it called. My guess it is called by DataTemplate manager, if I can say so.
try to change this line:
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(StatusProgress),
new FrameworkPropertyMetadata(null, (d, e) => (d as StatusProgress).TextUpdated(e.OldValue as string)));
with this:
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(StatusProgress)
, new PropertyMetadata(""));

does WPF binding bypass the codebehind setter for dependencyproperties?

I may be doing this all wrong... so hang with me
I am making a user control with a property which the user can bind to. The in setter for the property, I bind the PropertyChanged listener to the property so I can react to changes to its state. The code behind for this user control looks like this:
public static readonly DependencyProperty NodeProperty =
DependencyProperty.Register("Node", typeof(MockRequirementWrapper), typeof(RecNode2));
public MockRequirementWrapper Node
{
get
{
return (MockRequirementWrapper)GetValue(NodeProperty);
}
set
{
if(Node != null)
Node.PropertyChanged -= Update;
SetValue(NodeProperty, value);
Node.PropertyChanged += new PropertyChangedEventHandler(Update);
OnPropertyChanged(this, "Node");
}
}
then, in another user control, I bind to this property a node I've created elsewhere like this:
<local:RecNode2 Node="{Binding}"/>
What I am finding is the recnode exists and is bound to a node... but if I put a breakpoint in the setter, it never gets called. Am I misunderstanding how the binding works? How do I add my listener when the node changes?
The framework will always call GetValue and SetValue directly, the property is just for convenience and sould never contain logic besides those calls.
If you want to do something on changes register a PropertyChangedCallback in the Metadata when registering the DependencyProperty.
Taken from http://msdn.microsoft.com/en-us/library/ms753358.aspx:
public static readonly DependencyProperty AquariumGraphicProperty = DependencyProperty.Register(
"AquariumGraphic",
typeof(Uri),
typeof(AquariumObject),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnUriChanged)
)
);
public Uri AquariumGraphic
{
get { return (Uri)GetValue(AquariumGraphicProperty); }
set { SetValue(AquariumGraphicProperty, value); }
}

Binding Dependency Properties

So here I come creating a user control. It consists of a treeview dropping down from a combobox.
Actually, there is a button with a control (DropTree) dropping down from its contextmenu. So I have a control DropTree.
public partial class DropTree : UserControl
{
public TreeView TreeView
{ get{return treeView;} }
public DropTree()
{ InitializeComponent(); }
}
to simplify it, I made the TreeView control public, then I have my main control which is called ComboTreeView.
Now I need to represent some treeview properties in it, so I define several dependency properties:
public static DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(ComboTreeView), new FrameworkPropertyMetadata { Inherits = true, IsNotDataBindable = false, DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });
public object SelectedItem
{
get { return GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
and in constructor it is:
public ComboTreeView()
{
InitializeComponent();
TreeViewControl.SetBinding(TreeView.SelectedItemProperty, new Binding("SelectedItem") { Source = this, Mode = BindingMode.TwoWay });
}
and it all seems ok, until i run it. It crashes saying that SelectedItem cannot be binded to data. I don't understand?
The same goes for ItemsSource and SelectedValue... but only SelectedValuePath property defined this way goes fine.
Can anybody help? Or is there any other way to bind it correctly?
PS: by the way, I need to use DataBinding for ComboTreeView in my code later.
Try to set the Binding on SelectedValue instead of SelectedItem.
TreeView.SelectedItem is a readonly property. You can't set it, whether explicitly or through binding. In order to select a node in a TreeView, you must set the TreeViewItem.IsSelected property to true.

Categories