Grid Binding not working with CLR properties - c#

I have a hexagon grid which I want to populate with some models inherited from labels (suggestions for a better class to use instead of labels are welcome). I want to bind a private variable (xPos for example) from my model to its grid properties.
I have these two models.
Unit
public class Unit : Label, INotifyPropertyChanged
{
public Unit() { } //Grass
public Unit(int x, int y)
{
this.xPos = x;
this.yPos = y;
this.mouseLeft = false;
this.mouseRight = false;
}
public static readonly RoutedEvent ClickEvent;
private int _xPos, _yPos;
private bool mouseLeft, mouseRight;
public int xPos
{
get { return _xPos; }
set
{
_xPos = value;
NotifyPropertyChanged("xPos");
}
}
public int yPos
{
get { return _yPos; }
set
{
_yPos = value;
NotifyPropertyChanged("yPos");
}
}
private string _type = "none";
public string type
{
get { return _type; }
set
{
_type = value;
}
}
static Unit()
{
ClickEvent = ButtonBase.ClickEvent.AddOwner(typeof(Unit));
}
public event RoutedEventHandler Click
{
add { AddHandler(ClickEvent, value); }
remove { RemoveHandler(ClickEvent, value); }
}
protected override void OnMouseDown(MouseButtonEventArgs e)
{
this.mouseLeft = e.LeftButton.ToString().Equals("Pressed");
this.mouseRight = e.RightButton.ToString().Equals("Pressed");
base.OnMouseDown(e);
CaptureMouse();
}
protected override void OnMouseUp(MouseButtonEventArgs e)
{
base.OnMouseUp(e);
if (this.mouseRight)
{
this.xPos = (int)this.GetValue(Grid.RowProperty);
this.yPos = (int)this.GetValue(Grid.ColumnProperty);
this.type = this.GetType().Name;
}
else if (this.mouseLeft)
{
MainWindow.objectInspector.selectedUnit = this;
}
else
{
MessageBox.Show("Kaos");
}
if (IsMouseCaptured)
{
ReleaseMouseCapture();
if (IsMouseOver)
RaiseEvent(new RoutedEventArgs(ClickEvent, this));
}
}
}
And this Model (inherited from Unit)
public class Soldier : Unit
{
public Soldier()
{
// get bitmapimage from resources and assign to img
Uri resourceUri = new Uri("Resources/Soldier.jpg", UriKind.Relative);
StreamResourceInfo streamInfo = Application.GetResourceStream(resourceUri);
BitmapFrame temp = BitmapFrame.Create(streamInfo.Stream);
var brush = new ImageBrush();
brush.ImageSource = temp;
this.Background = brush;
}
}
And this WPF
<local:Soldier xPos="10" yPos="5" Grid.Row="Binding Path=this.yPos" Grid.Column="Binding Path=this.xPos" />
<local:Soldier xPos="7" yPos="7" Grid.Row="Binding Path=this.yPos" Grid.Column="Binding Path=this.xPos" />
How can I bind the Soldiers Grid.Row to its yPos?

I can't understand why you've created such a misleading title for your question. You're not trying to bind to private variables... you're trying to bind to public properties like everyone else here. Having said that, have you tried using a Binding with RelativeSource?:
<local:Soldier xPos="10" yPos="5" Grid.Row="{Binding yPos, RelativeSource=
{RelativeSource Self}}" Grid.Column="{Binding xPos, RelativeSource=
{RelativeSource Self}}" />
<local:Soldier xPos="7" yPos="7" Grid.Row="{Binding yPos, RelativeSource=
{RelativeSource Self}}" Grid.Column="{Binding xPos, RelativeSource=
{RelativeSource Self}}" />

Related

Update string from different object's OnTouchAction

I have an object class that derives from BoxView. The object has TouchEffect attached and when the OnTouchAction starts, I change the object's properties.
I would also like to change the property of a label based on the text attached to the string that label is bound to.
What I did is I created an instance of the page that contains bindable string and label, then, I tried to change the value of string by referencing it in code inside the OnTouchAction method.
I don't get errors and the Breakpoint tells me that code arrives to the line, but the label is not being updated.
I am trying to update the string from the class that is not the same where the string is.
Is there anyone who could help me out here?
class Element : BoxView
{
List<long> ids = new List<long>();
MainPage mainPage = new MainPage();
public event EventHandler StatusChanged;
public Element()
{
TouchEffect effect = new TouchEffect();
effect.TouchAction += OnTouchEffectAction;
Effects.Add(effect);
}
public Color DefaultColor { set; get; }
public Color HighlightColor { set; get; }
public bool IsPressed { private set; get; }
void OnTouchEffectAction(object sender, TouchActionEventArgs args)
{
switch (args.Type)
{
case TouchActionType.Pressed:
AddToList(args.Id);
mainPage.LeftLabelText = "entered";
break;
case TouchActionType.Entered:
if (args.IsInContact)
{
AddToList(args.Id);
mainPage.LeftLabelText = "entered";
}
break;
case TouchActionType.Moved:
break;
case TouchActionType.Released:
case TouchActionType.Exited:
RemoveFromList(args.Id);
break;
}
}
void AddToList(long id)
{
if (!ids.Contains(id))
{
ids.Add(id);
}
CheckList();
}
void RemoveFromList(long id)
{
if (ids.Contains(id))
{
ids.Remove(id);
}
CheckList();
}
void CheckList()
{
if (IsPressed != ids.Count > 0)
{
IsPressed = ids.Count > 0;
Color = IsPressed ? HighlightColor : DefaultColor;
mainPage.LeftLabelText = "entered";
StatusChanged?.Invoke(this, EventArgs.Empty);
}
}
}
and the MainPage relevant code:
Element element = new Element();
element.HighlightColor = Color.Accent;
element.DefaultColor = Color.Transparent;
element.Color = bar.DefaultColor;
element.HeightRequest = sGrid.Height;
element.VerticalOptions = LayoutOptions.End;
(...) // adding element view to the grid.
The string:
public string _leftLabelText = "testing";
public string LeftLabelText
{
get => _leftLabelText;
set
{
_leftLabelText = value;
NotifyPropertyChanged("LeftLabelText");
}
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged2;
protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged2?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
<Label x:Name="leftLabel" x:FieldModifier="public" Text="{Binding LeftLabelText, Mode=TwoWay}" TextColor="Black" FontSize="10" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand"/>

Slide up animation when IsVisible is changed in xaml xamarin and C#

I have a class for animation behavior like:
public class BaseAnimationBehavior : Behavior<View>
{
protected View associatedObject;
protected Easing _easingFunction;
private readonly BindableProperty EasingFunctionProperty = BindableProperty.Create(nameof(EasingFunction), typeof(string), typeof(BaseAnimationBehavior), defaultValue: "Linear", propertyChanged: (b, o, n) => OnEasingFunctionChanged(b, (string)o, (string)n));
private readonly BindableProperty ScaleProperty = BindableProperty.Create(nameof(Scale), typeof(double), typeof(BaseAnimationBehavior), defaultValue: 1.25);
public string EasingFunction
{
get { return (string)GetValue(EasingFunctionProperty); }
set { SetValue(EasingFunctionProperty, value); }
}
public double Scale
{
get { return (double)GetValue(ScaleProperty); }
set { SetValue(ScaleProperty, value); }
}
protected override void OnAttachedTo(View bindable)
{
associatedObject = bindable;
associatedObject.SizeChanged += AnimateItem;
}
protected override void OnDetachingFrom(View bindable)
{
associatedObject.SizeChanged -= AnimateItem;
}
private static Easing GetEasing(string easingName)
{
switch (easingName)
{
case "BounceIn": return Easing.BounceIn;
case "BounceOut": return Easing.BounceOut;
case "CubicInOut": return Easing.CubicInOut;
case "CubicOut": return Easing.CubicOut;
case "Linear": return Easing.Linear;
case "SinIn": return Easing.SinIn;
case "SinInOut": return Easing.SinInOut;
case "SinOut": return Easing.SinOut;
case "SpringIn": return Easing.SpringIn;
case "SpringOut": return Easing.SpringOut;
default: throw new ArgumentException(easingName + " is not valid");
}
}
private static void OnEasingFunctionChanged(BindableObject bindable, string oldvalue, string newvalue)
{
var obj = bindable as BaseAnimationBehavior;
if (obj == null)
{
return;
}
obj.EasingFunction = newvalue;
obj._easingFunction = GetEasing(newvalue);
}
private void AnimateItem(object sender, EventArgs e)
{
await associatedObject.TranslateTo(associatedObject.TranslationX, associatedObject.TranslationY - 10, 10, _easingFunction);
await associatedObject.TranslateTo(associatedObject.TranslationX, associatedObject.TranslationY + 10, 900, _easingFunction);
}
}
in XAML page, I apply animation like:
<StackLayout IsVisible="{Binding AProp}">
<Entry Text="{Binding AField}" IsEnabled="True">
<Entry.Behaviors>
<Entry.Behaviors:BaseAnimationBehavior EasingFunction="SinInOut" />
</Entry.Behaviors>
</Entry>
</StackLayout>
When AProp becomes true then animation occur because of SizeChanged event.
When AProp becomes false then animation won't run or won't be visible because entire StackLayout is hidden.
I use MVVM and I have a view model and it is binded to view like:
public class MyViewModel
{
public bool AProp { get { return _prop; } set { _prop = value; RaisePropertyChanged ....; } }
public string AField { get { return _field; } set { _field = value; RaisePropertyChanged ....; } }
public void DoSomething() {
if(condition) { AProp = true; } else { AProp = false; }
}
}
How to achieve the situation when hide element, to animate first and then hide it ?
If you are hiding using the View Model you would need to send some kind of signal to the view that the property has changed.
If you have to hide the control from the View Model for some reason I would suggest
overriding the RaisePropertyChanged in your view model
rise an event on the property name is AProb
subscribe to that event in the view
finally start your animation manually by giving the Entry a name

How to enable/disable an attached behavior using a boolean property in the ViewModel

The title says what I am attempting to do. Here is what I have:
I am using this CodeProject contribution to attach a RubberBand behavior to a ListBox, so that I can drag-select using the mouse. I was able to modify it, so that I can disable it during instantiation of the ListBox for when I need the ListBox to be non-interactive and only show items.
The ListBox is embeded in a UserControl and contains a canvas that displays elements and in one section of my program I needed the UserControl to be a non-interactive representation of those elements, whereas in the other I needed it to be interactive. However now, I need to be able to toggle between these two states and unfortunately that does not work with the implementation I have ATM and I do not understand why.
I have bound the attached property 'IsActive', which I added in my modified RubberBand-version (see code below) to the property 'IsEditable' of my UserControl-ViewModel, but for some reason the method 'IsActiveProperty_Changed' does not execute, when 'IsEditable' changes.
This is I am using the behavior and binding to 'IsEditable':
<i:Interaction.Behaviors>
<behavior:RubberBandBehavior IsActive="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.IsEditable}"/>
</i:Interaction.Behaviors>
I have also tried this, which also does not work:
<behavior:RubberBandBehavior IsActive="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.IsEditable, UpdateSourceTrigger=PropertyChanged}"/>
To disable the hit-detection of the ListBox, I am also binding to 'IsEditable', which does work fine:
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.IsEditable}" Value="False">
<Setter Property="IsHitTestVisible" Value="False" />
<Setter Property="Focusable" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
I therefore suspect, that it has to do with my implementation/modification of RubberBandBehavior, since I am still unexperienced to implementing Attached Properties. I hope somebody can spot my error.
Modified RubberBandBehavior.cs
public class RubberBandBehavior : Behavior<ListBox>
{
private RubberBandAdorner band;
private AdornerLayer adornerLayer;
public static readonly DependencyProperty IsActiveProperty =
DependencyProperty.Register("IsActive", typeof(bool), typeof(RubberBandBehavior),
new PropertyMetadata(IsActiveProperty_Changed));
private static void IsActiveProperty_Changed(DependencyObject sender,
DependencyPropertyChangedEventArgs args)
{
RubberBandBehavior rubberBandBehavior = (RubberBandBehavior)sender;
if (args.Property.Name == "IsActive")
{
bool newIsActiveValue = (bool)args.NewValue;
bool oldIsActiveValue = (bool)args.OldValue;
if (newIsActiveValue != oldIsActiveValue)
{
rubberBandBehavior.IsActive = newIsActiveValue;
if (rubberBandBehavior.AssociatedObject != null)
{
if (newIsActiveValue == true)
{
rubberBandBehavior.AttachBehavior();
}
else
{
rubberBandBehavior.DetachBehavior();
}
}
}
}
}
public bool IsActive
{
get { return (bool)GetValue(IsActiveProperty); }
set { SetValue(IsActiveProperty, value); }
}
protected override void OnAttached()
{
AssociatedObject.Loaded += new System.Windows.RoutedEventHandler(AssociatedObject_Loaded);
base.OnAttached();
}
void AssociatedObject_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
if (IsActive == true)
{
AttachBehavior();
}
}
protected override void OnDetaching()
{
AssociatedObject.Loaded -= new System.Windows.RoutedEventHandler(AssociatedObject_Loaded);
base.OnDetaching();
}
private void AttachBehavior()
{
band = new RubberBandAdorner(AssociatedObject);
adornerLayer = AdornerLayer.GetAdornerLayer(AssociatedObject);
adornerLayer.Add(band);
}
private void DetachBehavior()
{
adornerLayer.Remove(band);
}
}
RubberBandAdorner.cs:
public class RubberBandAdorner : Adorner
{
private Point startpoint;
private Point currentpoint;
private Brush brush;
private bool flag;
private ScrollViewer viewer;
private ScrollBar scrollbar;
public RubberBandAdorner(UIElement adornedElement)
:base(adornedElement)
{
IsHitTestVisible = false;
adornedElement.MouseMove += new MouseEventHandler(adornedElement_PreviewMouseMove);
adornedElement.MouseLeftButtonDown += new MouseButtonEventHandler(adornedElement_PreviewMouseLeftButtonDown);
adornedElement.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(adornedElement_PreviewMouseLeftButtonUp);
brush = new SolidColorBrush(SystemColors.HighlightColor);
brush.Opacity = 0.3;
}
void adornedElement_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
DisposeRubberBand();
}
void adornedElement_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
ListBox _selector = AdornedElement as ListBox;
if (_selector.SelectedItems != null && (_selector.SelectionMode == SelectionMode.Extended || _selector.SelectionMode == SelectionMode.Multiple))
{
_selector.SelectedItems.Clear();
}
startpoint = Mouse.GetPosition(this.AdornedElement);
Mouse.Capture(_selector);
flag = true;
}
public static childItem FindVisualChild<childItem>(DependencyObject obj)
where childItem : DependencyObject
{
// Search immediate children first (breadth-first)
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is childItem)
return (childItem)child;
else
{
childItem childOfChild = FindVisualChild<childItem>(child);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}
void adornedElement_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed && flag)
{
currentpoint = Mouse.GetPosition(AdornedElement);
Selector _selector = AdornedElement as Selector;
if (viewer == null)
{
viewer = FindVisualChild<ScrollViewer>(_selector);
}
if (scrollbar == null)
{
scrollbar = FindVisualChild<ScrollBar>(viewer);
}
if (_selector.Items.Count > 0)
{
if (currentpoint.Y > ((FrameworkElement)AdornedElement).ActualHeight && viewer.VerticalOffset < _selector.ActualHeight && scrollbar.Visibility == System.Windows.Visibility.Visible)
{
startpoint.Y -= 50;
}
else if (currentpoint.Y < 0 && viewer.VerticalOffset > 0 && scrollbar.Visibility == System.Windows.Visibility.Visible)
{
startpoint.Y += 50;
}
}
InvalidateVisual();
foreach (var obj in _selector.Items)
{
ListBoxItem item = _selector.ItemContainerGenerator.ContainerFromItem(obj) as ListBoxItem;
if (item != null)
{
Point point = item.TransformToAncestor(AdornedElement).Transform(new Point(0, 0));
Rect bandrect = new Rect(startpoint, currentpoint);
Rect elementrect = new Rect(point.X, point.Y, item.ActualWidth, item.ActualHeight);
if (bandrect.IntersectsWith(elementrect))
{
item.IsSelected = true;
}
else
{
item.IsSelected = false;
}
}
}
}
}
protected override void OnRender(DrawingContext drawingContext)
{
Rect rect = new Rect(startpoint, currentpoint);
drawingContext.DrawGeometry(brush, new Pen(SystemColors.HighlightBrush, 1), new RectangleGeometry(rect));
base.OnRender(drawingContext);
}
private void DisposeRubberBand()
{
currentpoint = new Point(0, 0);
startpoint = new Point(0, 0);
AdornedElement.ReleaseMouseCapture();
InvalidateVisual();
flag = false;
}
}
Update:
Here is the code for the IsEditable property of the ViewModel. Note that I am using the RaisePropertyChanged method from MvvmLight:
private bool isEditable;
public bool IsEditable
{
get { return isEditable; }
set {
if(value != isEditable)
{
isEditable = value;
RaisePropertyChanged("IsEditable");
}
}
}
Your problem is that IsActive is NOT an AttachedProperty, just a regular DependencyProperty.
Remove the DP. This code should be removed:
public static readonly DependencyProperty IsActiveProperty =
DependencyProperty.Register("IsActive", typeof(bool), typeof(RubberBandBehavior),
new PropertyMetadata(IsActiveProperty_Changed));
public bool IsActive
{
get { return (bool)GetValue(IsActiveProperty); }
set { SetValue(IsActiveProperty, value); }
}
And then add IsActive as an attached property:
public static bool GetIsActive(DependencyObject obj)
{
return (bool)obj.GetValue(IsActiveProperty);
}
public static void SetIsActive(DependencyObject obj, bool value)
{
obj.SetValue(IsActiveProperty, value);
}
public static readonly DependencyProperty IsActiveProperty =
DependencyProperty.RegisterAttached("IsActive", typeof(bool), typeof(RubberBandBehavior), new PropertyMetadata(IsActiveProperty_Changed));
You will have to change the code that was setting/getting IsActive as well:
rubberBandBehavior.IsActive = newIsActiveValue;
becomes
rubberBandBehavior.SetValue(RubberBandBehavior.IsActiveProperty, newIsActiveValue);
And
if (IsActive == true)
becomes
if (this.GetValue(IsActiveProperty).Equals(true))
Although, I should mention that it is not necessary to execute the SetValue line since it would already be set to the newIsActiveValue... shouldn't hurt anything but it doesn't really do anything either. Nor is it necessary to check if the old and new values are different, if they weren't different then IsActiveProperty_Changed would not have been called.
Edit:
Here is the complete RubberBandBehavior.cs:
public class RubberBandBehavior : Behavior<ListBox>
{
private RubberBandAdorner band;
private AdornerLayer adornerLayer;
public static bool GetIsActive(DependencyObject obj)
{
return (bool)obj.GetValue(IsActiveProperty);
}
public static void SetIsActive(DependencyObject obj, bool value)
{
obj.SetValue(IsActiveProperty, value);
}
public static readonly DependencyProperty IsActiveProperty =
DependencyProperty.RegisterAttached("IsActive", typeof(bool), typeof(RubberBandBehavior), new PropertyMetadata(IsActiveProperty_Changed));
private static void IsActiveProperty_Changed(DependencyObject sender,
DependencyPropertyChangedEventArgs args)
{
RubberBandBehavior rubberBandBehavior = (RubberBandBehavior)sender;
if (args.Property.Name == "IsActive")
{
bool newIsActiveValue = (bool)args.NewValue;
if (rubberBandBehavior.AssociatedObject != null)
{
if (newIsActiveValue == true)
{
rubberBandBehavior.AttachBehavior();
}
else
{
rubberBandBehavior.DetachBehavior();
}
}
}
}
protected override void OnAttached()
{
AssociatedObject.Loaded += new System.Windows.RoutedEventHandler(AssociatedObject_Loaded);
base.OnAttached();
}
void AssociatedObject_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
if (this.GetValue(IsActiveProperty).Equals(true))
{
AttachBehavior();
}
}
protected override void OnDetaching()
{
AssociatedObject.Loaded -= new System.Windows.RoutedEventHandler(AssociatedObject_Loaded);
base.OnDetaching();
}
private void AttachBehavior()
{
band = new RubberBandAdorner(AssociatedObject);
adornerLayer = AdornerLayer.GetAdornerLayer(AssociatedObject);
adornerLayer.Add(band);
}
private void DetachBehavior()
{
adornerLayer.Remove(band);
}
}
RubberBandAdorner is using ContainerFromItem which will not work when your items are the same (a list of strings with the same text, for example). I have modified the code to use ContainerFromIndex. The outer foreach has been changed to a for loop.
In RubberBandAdorner.cs, in the adornedElement_PreviewMouseMove method update part of the code to this:
//foreach (var obj in _selector.Items)
//{
// ListBoxItem item = _selector.ItemContainerGenerator.ContainerFromItem(obj) as ListBoxItem;
for (int i=0; i<_selector.Items.Count; i++)
{
ListBoxItem item =_selector.ItemContainerGenerator.ContainerFromIndex(i) as ListBoxItem;
if (item != null)
{
Point point = item.TransformToAncestor(AdornedElement).Transform(new Point(0, 0));
Rect bandrect = new Rect(startpoint, currentpoint);
Rect elementrect = new Rect(point.X, point.Y, item.ActualWidth, item.ActualHeight);
if (bandrect.IntersectsWith(elementrect))
{
item.IsSelected = true;
}
else
{
item.IsSelected = false;
}
}
}

Setting root folder of HierarchicalDataTemplate WPF

I have the following TreeView:
<TreeView x:Name="Folders" Grid.Column="0" SelectedItemChanged="Folders_SelectedItemChanged" ItemsSource="{Binding Items}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type Local:OpenFolderItem}" ItemsSource="{Binding Children}" >
<StackPanel Orientation="Horizontal" VerticalAlignment="Stretch" Margin="0,2,0,2">
<Image Source="{Binding Path=Image, Mode=OneTime}" Stretch="Fill" />
<TextBlock Text="{Binding Name}" Margin="5,0" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
In the code-behind, I would like to change the root directory so that it auto-expands to that directory.
For example:
The following image shows what happens when I open a dialog:
Say I wish to start with the directory: "E:\Sequences", when I start the dialog, I would like it to look like this:
Here's the VM:
Update 1
public class OpenFolderItem : ViewModelBase
{
#region Private Members
private string m_path;
ICollection<OpenFolderItem> m_children;
bool m_isSelected;
#endregion Private Members
#region Constructors
public OpenFolderItem() { }
public OpenFolderItem(string path) { Path = path; }
#endregion
#region Properties
public bool IsExpanded { get; set; }
public string Name { get; set; }
public string Path
{
get
{
return m_path;
}
set
{
m_path = value;
}
}
public ImageSource Image { get; set; }
public virtual ICollection<OpenFolderItem> Children
{
get { return m_children ?? (m_children = LoadChildren()); }
set { m_children = value; }
}
#endregion Properties
#region Private Functions
private ICollection<OpenFolderItem> LoadChildren()
{
var items = new List<OpenFolderItem>();
try
{
items.AddRange(Directory.GetDirectories(Path).Select(directory => new OpenFolderItem(directory)
{
Name = System.IO.Path.GetFileName(directory),
Image = FileInfoHelper.GetFolderImage(false),
IsExpanded = true
}));
items = items.OrderBy(o => o.Path , new Comparer.NaturalStringComparer()).ToList();
}
catch (UnauthorizedAccessException) { }
catch (ArgumentException) { }
catch (DirectoryNotFoundException) { }
return new ReadOnlyCollection<OpenFolderItem>(items);
}
#endregion Private Functions
}
And here's the Xaml.cs:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
namespace OpenDialogs
{
/// <summary>
/// Interaction logic for OpenDialogView.xaml
/// </summary>
public partial class OpenDialogView
{
#region Private Members
private Window m_window;
#endregion Private Members
#region Constructor
/// <summary>
/// The OpenDialogView's constructor.
/// </summary>
public OpenDialogView()
{
InitializeComponent();
}
#endregion Constructor
#region Properties
public string IconFile { get; set; }
#endregion Properties
#region Private Functions
private void Folders_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
ViewModel.SelectedFolder = e.NewValue as OpenFolderItem;
}
private void OnShow(object sender, OpenDialogEventArgs e)
{
try
{
//var b = new OpenFolderItem();
//b.Name = "Sequences";
//b.Path = #"E:\Sequences";
//ViewModel.SelectedFolder = b;
//ItemCollection ic = Folders.Items;
//string yourNode = "Sequences";
//foreach (TreeViewItem tvi in ic)
//{
// if (yourNode.StartsWith(tvi.Tag.ToString()))
// {
// tvi.IsExpanded = true;
// break;
// }
//}
m_window = new Window
{
Content = this,
SizeToContent = SizeToContent.Manual,
ResizeMode = ResizeMode.CanResizeWithGrip,
WindowStyle = WindowStyle.SingleBorderWindow,
Title = e.Caption,
ShowInTaskbar = false,
Topmost = true,
Height = 600,
Width = 1000,
Owner = e.Owner,
WindowStartupLocation = e.StartupLocation,
};
if (!String.IsNullOrEmpty(IconFile))
m_window.Icon = BitmapFrame.Create(new Uri("pack://application:,,,/" + IconFile, UriKind.RelativeOrAbsolute));
m_window.ShowDialog();
}
catch (Exception)
{
Console.WriteLine();
}
}
private void OnClose(object sender, OpenDialogEventArgs e)
{
m_window.Close();
}
#endregion Private Functions
}
}
I'm pretty sure I'm being blocked by the 'HierarchicalDataTemplate'. Is that correct? Any way of making it work?
You'd have to loop through the nodes and set to necessary nodes IsExpanded properties to true.
Try this code in mainWindow.xaml.cs:
public MainWindow()
{
InitializeComponent();
ExtendTree();
}
private void ExtendTree()
{
ItemCollection ic = treeView.Items;
string yourNode = "Sequences";
foreach (var tvi in ic)
{
if (yourNode.StartsWith((TreeViewItem)tvi.Tag.ToString()))
{
(TreeViewItem)tvi.IsExpanded = true;
break;
}
}
}

UserControl DataBinding not working

Hy guys, I need your help again.
My XAML:
I would like to bind the Color of Line1 to my TestClassItem in XAML.
<Canvas Name="ElementCanvas">
<local:TestClass x:Name="TestClassItem" Width="50" Height="20" Position="20,100" LineColor="{Binding Stroke, ElementName=Line1}" ></local:TestClass>
<Line x:Name="Line1" X1="100" X2="300" Y1="50" Y2="50" Stroke="Red"/>
<Line x:Name="Line2" X1="100" X2="300" Y1="100" Y2="100" Stroke="{Binding Stroke, ElementName=Line1}" />
</Canvas>
My Created Class is pretty simple:
public class TestClass : Canvas
{
Line myLine = new Line();
public Color LineColor
{
get
{
return (Color)GetValue(LineStrokeProperty);
}
set
{
SetValue(LineStrokeProperty, value);
OnPropertyChanged("LineColor");
}
}
double X
{
get
{
return (double)Canvas.GetLeft(this);
}
set
{
Canvas.SetLeft(this, value);
OnPropertyChanged("X");
}
}
double Y
{
get
{
return (double)Canvas.GetTop(this) + Height / 2;
}
set
{
Canvas.SetTop(this, value - Height / 2);
OnPropertyChanged("Y");
}
}
public Point Position
{
get
{
return new Point(X, Y);
}
set
{
X = value.X;
Y = value.Y;
}
}
public static readonly DependencyProperty LineStrokeProperty = DependencyProperty.Register("LineColor", typeof(Color), typeof(TestClass), new FrameworkPropertyMetadata(Colors.Purple, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnLineStrokePropertyChanged), new CoerceValueCallback(OnLineStrokePropertyCoerceValue)), new ValidateValueCallback(OnLineStrokePropertyValidateValue));
private static bool OnLineStrokePropertyValidateValue(object value)
{
return true;
}
private static object OnLineStrokePropertyCoerceValue(DependencyObject d, object baseValue)
{
return (Color)baseValue;
}
private static void OnLineStrokePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((TestClass)d).SetValue(LineStrokeProperty, (Color)e.NewValue);
}
public TestClass()
{
DataContext = this;
Background = Brushes.Yellow;
SnapsToDevicePixels = true;
Binding b_width = new Binding("Width");
b_width.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
myLine.SetBinding(Line.X2Property, b_width);
Binding b_y1 = new Binding("Height");
b_y1.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
b_y1.Converter = new DoubleTwicer(); //Divides Height by 2
myLine.SetBinding(Line.Y1Property, b_y1);
Binding b_y2 = new Binding("Height");
b_y2.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
b_y2.Converter = new DoubleTwicer();
myLine.SetBinding(Line.Y2Property, b_y2);
Binding b_stroke = new Binding("LineColor");
b_stroke.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
b_stroke.Converter = new RaColorToSolidBrush();
myLine.SetBinding(Line.StrokeProperty, b_stroke);
this.Children.Add(myLine);
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
Why doesn't it work?
Does anybody know how to Debug (see Values of bindings in Visual Studio?)
Thank you sou much!!!!
First of all! Thank you guys you already helped me but it works but not completely (DataContext = this; might be the problem so leave it:
public Brush LineColor
{
get
{
return (Brush)GetValue(LineStrokeProperty);
}
set
{
SetValue(LineStrokeProperty, value);
OnPropertyChanged("LineColor");
}
}
public static readonly DependencyProperty LineStrokeProperty = DependencyProperty.Register("LineColor", typeof(Brush), typeof(RaClickableLine), new FrameworkPropertyMetadata(Brushes.White, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnLineStrokePropertyChanged), new CoerceValueCallback(OnLineStrokePropertyCoerceValue)), new ValidateValueCallback(OnLineStrokePropertyValidateValue));
private static bool OnLineStrokePropertyValidateValue(object value)
{
return true;
}
private static object OnLineStrokePropertyCoerceValue(DependencyObject d, object baseValue)
{
return (Brush)baseValue;
}
private static void OnLineStrokePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((RaClickableLine)d).SetValue(LineStrokeProperty, (Brush)e.NewValue);
}
public RaClickableLine()
{
SetValue(FrameworkElement.NameProperty, "ClickableLine");
Background = Brushes.AliceBlue;
SnapsToDevicePixels = true;
myLine.Stroke = Brushes.Blue;
myLine.X1 = 0;
myLine.X2 = ActualWidth;
myLine.Y1 = 10;
myLine.Y2 = 10;
Binding b_width = new Binding();
b_width.ElementName = "ClickableLine";
b_width.Path = new PropertyPath("Width");
b_width.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
myLine.SetBinding(Line.X2Property, b_width);
Children.Add(myLine);
}
It even don't show me the line.
If I leave b_width.ElementName = "ClickableLine"; and add DataContext = this; the line appears.

Categories