I want to write a custom FrameworkElement which host Visuals. My first attempt was to create an instance of ContainerVisual and write a wrapper property for ContainerVisual.Children and then set it as ContentProperty so I can and Visuals via XAML. But VisualCollection does only implement ICollection and not IList or any supported interface and VisualCollection is selead so I can't implement IList on my own.
How can I hostvisuals and let them add declaratively using XAML?
Okay, long time ago but here is the solution I found that time back...
The Collection:
Note the hack comments.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using System.Collections.ObjectModel;
using WPF.Controls.Primitives;
namespace WPF.Controls.Core
{
public class PrimitiveCollection : ObservableCollection<Primitive>
{
protected PrimitiveContainerVisual _owner;
public PrimitiveCollection(PrimitiveContainerVisual owner)
: base()
{
if (owner == null)
throw new ArgumentNullException("owner");
_owner = owner;
}
protected override void ClearItems()
{
foreach (var item in this)
{
item.IsDirtyChanged -= new IsDirtyChangedHandler(item_IsDirtyChanged);
_owner.InternalRemoveVisualChild(item);
}
base.ClearItems();
}
protected override void InsertItem(int index, Primitive item)
{
if (item != null && item.Parent != null)
throw new ArgumentNullException("Visual has parent");
item.IsDirtyChanged += new IsDirtyChangedHandler(item_IsDirtyChanged);
_owner.InternalAddVisualChild(item);
base.InsertItem(index, item);
}
protected override void RemoveItem(int index)
{
Primitive item = this[index];
item.IsDirtyChanged -= new IsDirtyChangedHandler(item_IsDirtyChanged);
_owner.InternalRemoveVisualChild(item);
base.RemoveItem(index);
}
protected override void OnPropertyChanged(System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
}
void item_IsDirtyChanged(object sender, PrimitiveChangedEventArgs e)
{
if(e.IsDirty)
_owner.RequestRedraw();
}
}
}
And the Control which you can use in XAML
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using WPF.Controls.Primitives;
using System.Windows;
using System.Reflection;
namespace WPF.Controls.Core
{
public class PrimitiveContainerVisual : Visual
{
private PrimitiveCollection _primitives;
private PropertyInfo _contentBoundsPropInfo;
private PropertyInfo _descendantBoundsPropInfo;
public PrimitiveCollection Children
{
get { return _primitives; }
set { _primitives = value; }
}
public Rect ContentBounds
{
// HACK access internal property of Visual
get { return (Rect)_contentBoundsPropInfo.GetValue(this, null); }
}
public Rect DescendantBounds
{
// HACK access internal property of Visual
get { return (Rect)_descendantBoundsPropInfo.GetValue(this, null); }
}
public PrimitiveContainerVisual()
{
_primitives = new PrimitiveCollection(this);
Type thisType = this.GetType();
BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance;
_contentBoundsPropInfo = thisType.GetProperty("VisualContentBounds", flags);
_descendantBoundsPropInfo = thisType.GetProperty("VisualDescendantBounds", flags);
}
internal void InternalAddVisualChild(Primitive prim)
{
this.AddVisualChild(prim);
}
internal void InternalRemoveVisualChild(Primitive prim)
{
this.RemoveVisualChild(prim);
}
public bool RequestRedraw()
{
UIElement uiParent = VisualParent as UIElement;
if (uiParent != null)
{
uiParent.InvalidateVisual();
return true;
}
else
return false;
}
}
}
Related
I have a simple WinForm with a DataGridView that shows record with Entity Framework.
My problem is that New Row feature appears only if the DataGridView is empty.
How is the problem?
Thank you in advance.
Luis
PS
Here some details of the WinForm class:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using GestioneFormazione;
namespace MpFormazione
{
public partial class MpFormazione : Form
{
public MpFormazione()
{
InitializeComponent();
this.dataGridView1.CellClick += DataGridView1_CellClick;
this.dataGridView1.AllowUserToAddRows = true;
this.dataGridView1.VirtualMode = true;
this.dataGridView1.AutoGenerateColumns = false;
}
private void DataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == this.ButtonColumunIndex)
{
if (e.RowIndex == 0)
{
Cliente cliente = new Cliente();
cliente.ID = Guid.NewGuid();
if (dataGridView1.Rows[0].Cells[1].Value != null)
cliente.Nome = dataGridView1.Rows[0].Cells[1].Value.ToString();
SaveToDb(cliente);
}
}
}
private void SaveToDb(Cliente cliente)
{
using (var context = new MPFORMAZIONEEntities())
{
context.Cliente.Add(cliente);
context.SaveChanges();
}
}
private void clienteBindingSource_CurrentChanged(object sender, EventArgs e)
{
}
private void ClienteBindingSource_AddingNew(object sender, System.ComponentModel.AddingNewEventArgs e)
{
}
private int ButtonColumunIndex
{
get
{
return 2;
}
}
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
}
private void MpFormazione_Load(object sender, EventArgs e)
{
using (var context = new MPFORMAZIONEEntities())
{
this.dataGridView1.DataSource = context.Cliente.ToList<Cliente>();
}
}
}
}
The page has only this code, and the Entity Framework for "Cliente" and "Dipendente" entities.
I do not know what that many parentheses and identifiers mean.
Fixing is really hard.
Please help me fix it.
Even when I could not make this change, I said that I had no paycheck.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace ChatBubbles
{
public class ItemHelper : DependencyObject
{
public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.RegisterAttached("IsChecked", typeof(bool?), typeof(ItemHelper), new PropertyMetadata(false, new PropertyChangedCallback(OnIsCheckedPropertyChanged)));
private static void OnIsCheckedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is Family && ((bool?)e.NewValue).HasValue)
foreach (Person p in (d as Family).Members)
ItemHelper.SetIsChecked(p, (bool?)e.NewValue);
if (d is Person)
{
int checked = ((d as Person).GetValue(ItemHelper.ParentProperty) as Family).Members.Where(x => ItemHelper.GetIsChecked(x) == true).Count();
int unchecked = ((d as Person).GetValue(ItemHelper.ParentProperty) as Family).Members.Where(x => GetIsChecked(x) == false).Count();
if (unchecked > 0 && checked > 0)
{
ItemHelper.SetIsChecked((d as Person).GetValue(ItemHelper.ParentProperty) as DependencyObject, null);
return;
}
if (checked > 0)
{
ItemHelper.SetIsChecked((d as Person).GetValue(ItemHelper.ParentProperty) as DependencyObject, true);
return;
}
ItemHelper.SetIsChecked((d as Person).GetValue(ItemHelper.ParentProperty) as DependencyObject, false);
}
}
}
}
public static void SetIsChecked(DependencyObject element, bool? IsChecked)
{
element.SetValue(ItemHelper.IsCheckedProperty, IsChecked);
}
public static bool? GetIsChecked(DependencyObject element)
{
return (bool?)element.GetValue(ItemHelper.IsCheckedProperty);
}
public static readonly DependencyProperty ParentProperty = DependencyProperty.RegisterAttached("Parent", typeof(object), typeof(ItemHelper));
public static void SetParent(DependencyObject element, object Parent)
{
element.SetValue(ItemHelper.ParentProperty, Parent);
}
public static object GetParent(DependencyObject element)
{
return (object)element.GetValue(ItemHelper.ParentProperty);
}
}
}
I am using Framework version 4.0,
My problem when Zoom, Canvas should not re-size. or children only zoom IN / OUT?
please suggest me.
Thanks
I have done this before, the solution I found was when ever the zoom-in, make zoom out to the items I want keep the same size.
So, the zoom is a scale transform, then always when the scale transform in the container zoom item increase, you need to apply a decreasing transform to the items (the items you want keep the size).
Here I have a sample code of an attached property that you can use later in xaml code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
using Cepha.View.Converter;
using Cepha.View.Util;
using Microsoft.Practices.ServiceLocation;
using WPFExtensions.Controls;
namespace Cepha.View.AttachedProperty
{
public static class KeepSizeOnZoomBehavior
{
#region KeppSizeOnZoom
public static bool GetKeppSizeOnZoom(DependencyObject obj)
{
return (bool) obj.GetValue(KeppSizeOnZoomProperty);
}
public static void SetKeppSizeOnZoom(DependencyObject obj, bool value)
{
obj.SetValue(KeppSizeOnZoomProperty, value);
}
// Using a DependencyProperty as the backing store for KeppSizeOnZoom. This enables animation, styling, binding, etc...
public static readonly DependencyProperty KeppSizeOnZoomProperty =
DependencyProperty.RegisterAttached("KeppSizeOnZoom", typeof (bool), typeof (KeepSizeOnZoomBehavior),
new PropertyMetadata(false, OnKeepSizeOnZoomPropertyChanged));
private static void OnKeepSizeOnZoomPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var uiElement = d as UIElement;
if (uiElement == null)
return;
if ((bool)e.NewValue)
{
var zoomContentPresenter = ViewUtils.GetParent(d, p => p is ZoomContentPresenter) as ZoomContentPresenter;
if (zoomContentPresenter == null)
return;
if (zoomContentPresenter.RenderTransform == null || !(zoomContentPresenter.RenderTransform is TransformGroup))
return;
var sourceScaleTransform =
(zoomContentPresenter.RenderTransform as TransformGroup).Children.FirstOrDefault(
c => c is ScaleTransform) as ScaleTransform;
if (sourceScaleTransform == null)
return;
if (uiElement.RenderTransform == null || !(uiElement.RenderTransform is TransformGroup))
{
uiElement.RenderTransform = new TransformGroup();
}
var scaleTransform =
(uiElement.RenderTransform as TransformGroup).Children.FirstOrDefault(c => c is ScaleTransform) as
ScaleTransform;
var inverseConverter = ServiceLocator.Current.GetInstance<InverseConverter>();
if (scaleTransform == null)
{
scaleTransform =
new ScaleTransform(
(double) inverseConverter.Convert(sourceScaleTransform.ScaleX, typeof (double), null, null),
(double) inverseConverter.Convert(sourceScaleTransform.ScaleY, typeof (double), null, null), 0,
0);
(uiElement.RenderTransform as TransformGroup).Children.Add(scaleTransform);
}
BindingOperations.SetBinding(scaleTransform, ScaleTransform.ScaleXProperty,
new Binding("ScaleX")
{Source = sourceScaleTransform, Converter = inverseConverter});
BindingOperations.SetBinding(scaleTransform, ScaleTransform.ScaleYProperty,
new Binding("ScaleY")
{Source = sourceScaleTransform, Converter = inverseConverter});
if (d is FrameworkElement)
{
(d as FrameworkElement).Unloaded += OnElementUnloaded;
}
}
else
{
ClearScaleYXBinding(uiElement);
}
}
private static void OnElementUnloaded(object sender, RoutedEventArgs e)
{
var uiElement = sender as UIElement;
if (uiElement == null)
return;
ClearScaleYXBinding(uiElement);
((FrameworkElement) sender).Unloaded -= OnElementUnloaded;
}
private static void ClearScaleYXBinding(UIElement uiElement)
{
if (!(uiElement.RenderTransform is TransformGroup))
return;
var scaleTransform =
(uiElement.RenderTransform as TransformGroup).Children.FirstOrDefault(c => c is ScaleTransform) as
ScaleTransform;
if (scaleTransform == null)
return;
BindingOperations.ClearBinding(scaleTransform, ScaleTransform.ScaleXProperty);
BindingOperations.ClearBinding(scaleTransform, ScaleTransform.ScaleYProperty);
}
#endregion
}
}
The inverse converter:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows.Data;
namespace Cepha.View.Converter
{
public class InverseConverter:IValueConverter
{
#region Implementation of IValueConverter
/// <summary>
/// Converts a value.
/// </summary>
/// <returns>
/// A converted value. If the method returns null, the valid null value is used.
/// </returns>
/// <param name="value">The value produced by the binding source.</param><param name="targetType">The type of the binding target property.</param><param name="parameter">The converter parameter to use.</param><param name="culture">The culture to use in the converter.</param>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is double)
return 1/(double) value;
return 1/(float) value;
}
/// <summary>
/// Converts a value.
/// </summary>
/// <returns>
/// A converted value. If the method returns null, the valid null value is used.
/// </returns>
/// <param name="value">The value that is produced by the binding target.</param><param name="targetType">The type to convert to.</param><param name="parameter">The converter parameter to use.</param><param name="culture">The culture to use in the converter.</param>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is double)
return 1 / (double)value;
return 1 / (float)value;
}
#endregion
}
}
You can use this in styles:
<Style x:Key="PointListBoxItemStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="Transparent"/>
...
<Setter Property="AttachedProperty:KeepSizeOnZoomBehavior.KeppSizeOnZoom" Value="True"/>
...
Or you can use it directly on visual items:
<Buttom AttachedProperty:KeepSizeOnZoomBehavior.KeppSizeOnZoom="True" .../>
Try this, maybe helps you...
EDIT
The ViewUtil is a simple static class for helping in some manage things, here is the code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media;
namespace Cepha.View.Util
{
public static class ViewUtils
{
public static bool AnyParent(DependencyObject item, Func<DependencyObject, bool> condition)
{
if (item == null)
return false;
var logicalParent = LogicalTreeHelper.GetParent(item);
var visualParent = VisualTreeHelper.GetParent(item);
return condition(item) || AnyParent(visualParent, condition);
}
public static DependencyObject GetParent(DependencyObject item, Func<DependencyObject, bool> condition)
{
if (item == null)
return null;
var logicalParent = LogicalTreeHelper.GetParent(item);
var visualParent = VisualTreeHelper.GetParent(item);
return condition(item) ? item : GetParent(visualParent, condition);
}
public static DependencyObject GetVisualChild(DependencyObject item, Func<DependencyObject, bool> condition)
{
if (item == null)
return null;
var q = new Queue<DependencyObject>();
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(item); i++)
{
var t = VisualTreeHelper.GetChild(item, i);
if (condition(t))
return t;
q.Enqueue(t);
}
while (q.Count > 0)
{
var subchild = q.Dequeue();
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(subchild); i++)
{
var t = VisualTreeHelper.GetChild(subchild, i);
if (condition(t))
return t;
q.Enqueue(t);
}
}
return null;
}
public static DependencyObject GetLogicalChild(DependencyObject item, Func<DependencyObject, bool> condition)
{
if (item == null)
return null;
var q = new Queue<DependencyObject>();
foreach (var w in LogicalTreeHelper.GetChildren(item))
{
var t = w as DependencyObject;
if (condition(t))
return t;
q.Enqueue(t);
}
while (q.Count > 0)
{
var subchild = q.Dequeue();
foreach (var w in LogicalTreeHelper.GetChildren(subchild))
{
var t = w as DependencyObject;
if (condition(t))
return t;
q.Enqueue(t);
}
}
return null;
}
}
}
Assign a ScaleTransform instance to the RenderTransform property of your Canvas. Smaller values 'zoom' out, large values 'zoom' in.
If you were to use the LayoutTransform property of your canvas, the size would change.
A little light reading on transformations, from Microsoft: http://msdn.microsoft.com/en-us/library/ms750596.aspx
I am attempting to create a region control that does the following trick
<wgc:RegionContentControl Region="HotDog">
<Label>Foo</Label>
<Label>Bar</Label>
</wgc:RegionContentControl>
<wgc:RegionControl Region="HotDog">
</wgc:RegionControl>
At run time and design time the controls defined in RegionContentControl
will get appended to RegionControl. I can use this to inject stuff into
status bars for example.
Anyway at runtime it works fine and sometimes in the designer it work.
However sometimes in the designer I get an error that
Element already has a logical parent. It must be detached from the
old parent before it is attached to the new one.
My code implementing the above pattern is below.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace My.Controls
{
public class RegionMessage {
public enum RegionAction {
Add,
Remove,
}
public string Region { get; set; }
public List<Control> Controls { get; set; }
public RegionAction Action { get; set; }
}
public class RegionControl : ItemsControl
{
public RegionControl()
{
ReactiveUI
.MessageBus.Current
.Listen<RegionMessage>()
.Subscribe(HandleRegionMessage);
}
public string Region
{
get { return (string)GetValue(RegionProperty); }
set { SetValue(RegionProperty, value); }
}
public static readonly DependencyProperty RegionProperty =
DependencyProperty.Register("Region", typeof(string), typeof(RegionControl), new PropertyMetadata(""));
private void HandleRegionMessage(RegionMessage obj)
{
if (obj.Region!=Region)
{
return;
}
if (obj.Action==RegionMessage.RegionAction.Add)
{
foreach (var item in obj.Controls)
{
this.Items.Add(item);
}
}
else
{
foreach (var item in obj.Controls)
{
this.Items.Remove(item);
}
}
}
}
[ContentProperty("Children")]
public class RegionContentControl : Control
{
static RegionContentControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(RegionContentControl), new FrameworkPropertyMetadata(typeof(RegionContentControl)));
}
public static readonly DependencyProperty ChildrenProperty =
DependencyProperty.Register("Children", typeof(List<Control>), typeof(RegionContentControl), new PropertyMetadata(new List<Control>()));
public List<Control> Children
{
get { return (List<Control>)GetValue(ChildrenProperty); }
set { SetValue(ChildrenProperty, value); }
}
public string Region
{
get { return (string)GetValue(RegionProperty); }
set { SetValue(RegionProperty, value); }
}
// Using a DependencyProperty as the backing store for Region. This enables animation, styling, binding, etc...
public static readonly DependencyProperty RegionProperty =
DependencyProperty.Register("Region", typeof(string), typeof(RegionContentControl), new PropertyMetadata(""));
public RegionContentControl()
{
this.LoadedObserver().Subscribe(Loaded);
}
private void Loaded(System.Reactive.EventPattern<RoutedEventArgs> obj)
{
ReactiveUI.MessageBus.Current.SendMessage(new RegionMessage()
{
Action = RegionMessage.RegionAction.Add
,
Controls = Children
,
Region = Region
});
}
}
}
I am sure that my problem involves that the controls still think they are attached to the RegionContentControl but I'm not sure how to detach them correctly. Any suggestions?
Removing the items from Children before broadcasting does the trick
List<Control> _HiddenChildren;
private void Loaded(System.Reactive.EventPattern<RoutedEventArgs> obj)
{
if (_HiddenChildren==null)
{
_HiddenChildren = Children;
this.Children = new List<Control>();
}
ReactiveUI.MessageBus.Current.SendMessage(new RegionMessage()
{ Action = RegionMessage.RegionAction.Add
, Controls = _HiddenChildren
, Region = Region
});
}
I am Performing a Tutorial I found in Expression Blend 4 for connecting to a SQL Server with WPF. After the final steps in VS12 when I do a build I get the following error.
Error 1 The type or namespace name 'DelegateCommand' could not be found (are you missing a using directive or an assembly reference?)
Error 2 The type or namespace name 'DelegateCommand' could not be found (are you missing a using directive or an assembly reference?)
When I do a Clean I do not get these errors.
My Target is .net 4.5 I also tried 4.0
My code That is erroring looks Like this. I bolded the two erroring lines. this is a file called Class1.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace AWADataSource
{
public class ProductPhotosCollection
{
**private DelegateCommand getDataCommand;
public DelegateCommand GetDataCommand { get { return getDataCommand; } }**
public ProductPhotosCollection()
{
getDataCommand = new DelegateCommand(delegate() { GetData(); });
}
public ObservableCollection<ProductPhoto> ProductPhotos
{ get { return this.productPhotos; } }
private ObservableCollection<ProductPhoto> productPhotos =
new ObservableCollection<ProductPhoto>();
private void GetData()
{
ProductPhotosTableAdapters.ProductPhotoTableAdapter da =
new ProductPhotosTableAdapters.ProductPhotoTableAdapter();
ProductPhotos.ProductPhotoDataTable dt = da.GetData();
productPhotos.Clear();
foreach (ProductPhotos.ProductPhotoRow row in dt)
{
productPhotos.Add(new ProductPhoto(
row.ProductPhotoID,
row.ThumbNailPhoto,
row.LargePhoto,
row.ModifiedDate));
}
}
}
public class ProductPhoto
{
// Public Accessors to the private properties.
public int ID { get { return id; } }
public ImageSource ThumbNailPhoto { get { return thumbNailPhoto; } }
public ImageSource LargePhoto { get { return largePhoto; } }
public DateTime ModifiedDate { get { return modifiedDate; } }
// Constructor.
public ProductPhoto(int id, byte[] thumbNailPhoto, byte[] largePhoto,
DateTime modifiedDate)
{
this.id = id;
this.thumbNailPhoto = ByteArrayToImageSource(thumbNailPhoto);
this.largePhoto = ByteArrayToImageSource(largePhoto);
this.modifiedDate = modifiedDate;
}
// Private properties.
private int id;
private ImageSource thumbNailPhoto;
private ImageSource largePhoto;
private DateTime modifiedDate;
// Supporting method.
private ImageSource ByteArrayToImageSource(byte[] data)
{
BitmapImage image = null;
if (null != data)
{
image = new BitmapImage();
image.BeginInit();
image.StreamSource = new System.IO.MemoryStream(data);
image.EndInit();
}
return image;
}
}
}
and my other file is called DelegateCommand.cs which was pretty much a copy and paist.
namespace AWDataSource
{
using System;
using System.Windows.Input;
///
/// DelegateCommand is a simplified version of ICommand in WPF. You can wrap one of these around any method,
/// and thus bind any command on any WPF object to your method.
///
/// DelegateCommand also supports an IsEnabled property that you can use to turn the command on and off.
///
public sealed class DelegateCommand : ICommand
{
// Remember the method so that it can be called at the right time.
private SimpleEventHandler handler;
// Maintain the enabled state.
private bool isEnabled = true;
// Type signature of the method that DelegateCommand works with - returns void, no arguments.
public delegate void SimpleEventHandler();
// Simple constructor: Pass in the method that needs to be called when the command executes.
public DelegateCommand(SimpleEventHandler handler)
{
this.handler = handler;
}
#region ICommand implementation
// Executing the command is as simple as calling the method.
void ICommand.Execute(object arg)
{
this.handler();
}
// Saying whether the command can be executed.
bool ICommand.CanExecute(object arg)
{
return this.IsEnabled;
}
// This is the event that the command architecture of WPF listens to so it knows when to update
// the UI on command enable/disable.
public event EventHandler CanExecuteChanged;
#endregion
// Public visibility of the isEnabled flag - note that when it is set, the event must be raised
// so that WPF knows to update any UI that uses this command.
public bool IsEnabled
{
get { return this.isEnabled; }
set
{
this.isEnabled = value;
this.OnCanExecuteChanged();
}
}
// Simple event propagation that makes sure that someone is listening to the event before raising it.
private void OnCanExecuteChanged()
{
if (this.CanExecuteChanged != null)
{
this.CanExecuteChanged(this, EventArgs.Empty);
}
}
}
}
ProductPhotosCollection is in namespace AWADataSource while DelegateCommand is in AWDataSource.
Probably a typo, but you either need to put them in the same namespace, or use a using to import the AWDataSource namespace into ProductPhotosCollection (or in your case "Class1.cs")