Click here to Skip to main content
13,836,661 members

Silverlight / WPF

 
PinnedHOW TO ANSWER A QUESTION PinPopular
Chris Maunder16-Jul-09 4:09
adminChris Maunder16-Jul-09 4:09 
PinnedHow to get an answer to your question PinPopular
Chris Maunder16-Jul-09 4:05
adminChris Maunder16-Jul-09 4:05 
QuestionHave two controls fill the MainWindow and resize automatically Pin
Mc_Topaz16-Jan-19 5:14
memberMc_Topaz16-Jan-19 5:14 
AnswerRe: Have two controls fill the MainWindow and resize automatically Pin
Richard Deeming16-Jan-19 9:07
mveRichard Deeming16-Jan-19 9:07 
GeneralRe: Have two controls fill the MainWindow and resize automatically Pin
Mc_Topaz16-Jan-19 20:22
memberMc_Topaz16-Jan-19 20:22 
QuestionHyperlink Context Menu Pin
Kevin Marois9-Jan-19 16:30
professionalKevin Marois9-Jan-19 16:30 
AnswerRe: Hyperlink Context Menu Pin
Richard Deeming10-Jan-19 1:32
mveRichard Deeming10-Jan-19 1:32 
GeneralRe: Hyperlink Context Menu Pin
Kevin Marois10-Jan-19 5:32
professionalKevin Marois10-Jan-19 5:32 
GeneralRe: Hyperlink Context Menu Pin
Kevin Marois10-Jan-19 6:31
professionalKevin Marois10-Jan-19 6:31 
QuestionTreeView Item Show Button Using Trigger Pin
Kevin Marois1-Jan-19 12:41
professionalKevin Marois1-Jan-19 12:41 
AnswerRe: TreeView Item Show Button Using Trigger Pin
Gerry Schmitz5-Jan-19 8:22
mveGerry Schmitz5-Jan-19 8:22 
GeneralRe: TreeView Item Show Button Using Trigger Pin
Kevin Marois7-Jan-19 8:31
professionalKevin Marois7-Jan-19 8:31 
GeneralRe: TreeView Item Show Button Using Trigger Pin
Gerry Schmitz7-Jan-19 9:39
mveGerry Schmitz7-Jan-19 9:39 
GeneralRe: TreeView Item Show Button Using Trigger Pin
Kevin Marois7-Jan-19 10:18
professionalKevin Marois7-Jan-19 10:18 
QuestionWPF Items Source get the visible items Pin
Paul M Gibson31-Dec-18 8:00
memberPaul M Gibson31-Dec-18 8:00 
AnswerRe: WPF Items Source get the visible items Pin
Gerry Schmitz1-Jan-19 7:42
mveGerry Schmitz1-Jan-19 7:42 
GeneralRe: WPF Items Source get the visible items Pin
Paul M Gibson2-Jan-19 7:22
memberPaul M Gibson2-Jan-19 7:22 
QuestionAd Control / monetization Pin
Super Lloyd18-Dec-18 14:02
memberSuper Lloyd18-Dec-18 14:02 
AnswerRe: Ad Control / monetization Pin
Pete O'Hanlon18-Dec-18 23:17
protectorPete O'Hanlon18-Dec-18 23:17 
GeneralRe: Ad Control / monetization Pin
Super Lloyd19-Dec-18 16:40
memberSuper Lloyd19-Dec-18 16:40 
AnswerRe: Ad Control / monetization Pin
Gerry Schmitz23-Dec-18 10:02
mveGerry Schmitz23-Dec-18 10:02 
GeneralRe: Ad Control / monetization Pin
Super Lloyd23-Dec-18 10:39
memberSuper Lloyd23-Dec-18 10:39 
GeneralRe: Ad Control / monetization Pin
Gerry Schmitz28-Dec-18 10:39
mveGerry Schmitz28-Dec-18 10:39 
QuestionValidation in WPF Pin
Kevin Marois18-Dec-18 7:59
professionalKevin Marois18-Dec-18 7:59 
AnswerRe: Validation in WPF Pin
Super Lloyd18-Dec-18 14:09
memberSuper Lloyd18-Dec-18 14:09 
yes you can.
Below find my the base ModelBase class that I use, that uses data anntoation to validate its property when OnPropertyChanged() is fired, with caveat it uses my own attributes, and might be missing some stuff.. but it should give you an idea! Wink | ;)
/// <summary>
/// Apparently this is not supported by Xamarin and/or PCL, hence provide custom simplistic implementation
/// </summary>
public abstract class ValidationAttribute : Attribute
{
    public abstract void Validate(ModelBase model, FastMember member, object value);

    public string ErrorMessage { get; set; }
}
/// <summary>
/// Base class for Model and ViewModel used in WPF, just basic <see cref="INotifyPropertyChanged"/>
/// and <see cref="INotifyDataErrorInfo"/> plumbing
/// </summary>
public class ModelBase : INotifyPropertyChanged, INotifyDataErrorInfo
{
    #region INotifyPropertyChanged

    public virtual void OnPropertyChanged([CallerMemberName]string name = "")
    {
        if (ValidatePropertyOnNotifyChanged)
        {
            if (string.IsNullOrEmpty(name))
            {
                Validate();
            }
            else
            {
                Validate(name);
            }
        }

        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }
    public event PropertyChangedEventHandler PropertyChanged;

    #endregion

    #region ValidatePropertyOnNotifyChanged Validate()

    public bool ValidatePropertyOnNotifyChanged
    {
        get { return mValidatePropertyOnNotifyChanged; }
        set
        {
            if (value == mValidatePropertyOnNotifyChanged)
                return;

            mValidatePropertyOnNotifyChanged = value;

            if (value)
                Validate();
        }
    }
    bool mValidatePropertyOnNotifyChanged;

    public bool Validate()
    {
        ClearErrors();
        foreach (var p in GetFastType().GetRuntimeMembers())
            Validate(p);
        return !HasErrors;
    }

    #endregion

    #region Errors (databinding error friend)

    public ErrorIndex Errors
    {
        get
        {
            if (eInfos == null)
                eInfos = new ErrorIndex(this);
            return eInfos;
        }
    }
    ErrorIndex eInfos;

    public class ErrorIndex : INotifyPropertyChanged
    {
        ModelBase model;
        internal ErrorIndex(ModelBase model)
        {
            this.model = model;
        }

        public ErrorData this[string property]
        {
            get
            {
                var errs = model.GetErrors(property).Cast<object>();
                return new ErrorData
                {
                    HasError = errs.Any(),
                    Error = errs.FirstOrDefault(),
                    Errors = errs,
                };
            }
        }
        internal void Updated(string pName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(pName)); }
        public event PropertyChangedEventHandler PropertyChanged;
    }
    public class ErrorData
    {
        public bool HasError { get; set; }
        public object Error { get; set; }
        public System.Collections.IEnumerable Errors { get; set; }
    }

    #endregion

    #region INotifyDataErrorInfo

    // make 'errors field' an auto initialize field, to get around deserialization issue
    List<Tuple<string, object>> errors
    {
        get
        {
            if (_errors == null)
                _errors = new List<Tuple<string, object>>();
            return _errors;
        }
    }
    List<Tuple<string, object>> _errors;

    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

    void RaiseErrorChanged(string pName)
    {
        pName = '[' + pName + ']';
        ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(pName));
        OnPropertyChanged(nameof(HasErrors));
        eInfos?.Updated(pName);
    }

    public System.Collections.IEnumerable GetErrors(string propertyName)
    {
        return errors.Where(x => x.Item1 == propertyName).Select(x => x.Item2);
    }

    public bool HasErrors { get { return errors.Count > 0; } }

    public void UpdateErrors(string propertyName, params object[] errors) { UpdateErrors(propertyName, (IEnumerable<object>)errors); }
    public void UpdateErrors(string propertyName, IEnumerable<object> errors)
    {
        bool had = false;
        for (int i = this.errors.Count - 1; i >= 0; i--)
        {
            if (this.errors[i].Item1 == propertyName)
            {
                had = true;
                this.errors.RemoveAt(i);
            }
        }
        bool will = false;
        if (errors != null)
        {
            errors.ForEach(x =>
            {
                will = true;
                this.errors.Add(Tuple.Create(propertyName, x));
            });
        }
        if (had || will)
        {
            RaiseErrorChanged(propertyName);
        }
    }

    public void AddErrors(string propertyName, params object[] errors) { AddErrors(propertyName, (IEnumerable<object>)errors); }
    public void AddErrors(string propertyName, IEnumerable<object> errors)
    {
        if (errors == null || errors.Count() == 0)
            return;

        errors.ForEach(x => this.errors.Add(Tuple.Create(propertyName, x)));

        RaiseErrorChanged(propertyName);
    }

    public void ClearErrors(string propertyName)
    {
        int count = 0;
        for (int i = errors.Count - 1; i >= 0; i--)
        {
            if (errors[i].Item1 == propertyName)
            {
                errors.RemoveAt(i);
                count++;
            }
        }
        if (count > 0)
            RaiseErrorChanged(propertyName);
    }
    public void ClearErrors()
    {
        var names = errors.Select(x => x.Item1).Distinct().ToList();
        errors.Clear();
        names.ForEach(x => RaiseErrorChanged(x));
    }

    /// <summary>
    /// Run attribute validation on a given property
    /// </summary>
    public bool Validate([CallerMemberName]string propertyName = null)
    {
        if (propertyName == null)
            return Validate();

        var m = GetFastType().GetRuntimeMembers().First(x => x.Name == propertyName);
        ClearErrors(propertyName);
        Validate(m);
        return !GetErrors(propertyName).Cast<object>().Any();
    }

    FastType GetFastType() { return meType ?? (meType = FastType.GetType((GetType()))); }
    FastType meType;

    protected virtual void Validate(FastMember pi)
    {
        if (pi == null)
            return;

        var value = pi.GetValue(this);
        var attrs = pi.GetAttributes().OfType<ValidationAttribute>();
        foreach (var attr in attrs)
            attr.Validate(this, pi, value);
    }

    #endregion

    #region extra utilities: GetLazyCommand() AddWatch()

    public DelegateCommand GetLazyCommand(Action onAction, [CallerMemberName]string name = null)
    {
        if (mCommands == null)
            mCommands = new Dictionary<string, DelegateCommand>();
        if (!mCommands.TryGetValue(name, out var result))
            mCommands[name] = result = new DelegateCommand(onAction);
        return result;
    }

    public DelegateCommand GetLazyCommand(Action<object> onAction, [CallerMemberName]string name = null)
    {
        if (mCommands == null)
            mCommands = new Dictionary<string, DelegateCommand>();
        if (!mCommands.TryGetValue(name, out var result))
            mCommands[name] = result = new DelegateCommand(onAction);
        return result;
    }

    public DelegateCommand GetLazyCommandAsync(Func<Task> onAction, [CallerMemberName]string name = null)
    {
        if (mCommands == null)
            mCommands = new Dictionary<string, DelegateCommand>();
        if (!mCommands.TryGetValue(name, out var result))
        {
            var cmd = new DelegateCommand();
            cmd.Action = async (o) =>
            {
                try
                {
                    cmd.IsEnabled = false;
                    await onAction();
                }
                finally { cmd.IsEnabled = true; }
            };
            mCommands[name] = result = cmd;
        }
        return result;
    }

    Dictionary<string, DelegateCommand> mCommands;

    public void AddWatch<TP>(Expression<Func<TP>> e, Action<TP> onChange)
    {
        if (watchers == null)
            watchers = new List<PropertyPath>();
        var w = PropertyPath.Create(e);
        watchers.Add(w);
        w.PropertyChanged += delegate { onChange(w.Value); };
    }
    List<PropertyPath> watchers;

    #endregion
}
A new .NET Serializer
All in one Menu-Ribbon Bar
Taking over the world since 1371!

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.


Advertise | Privacy | Cookies | Terms of Service
Web03 | 2.8.190114.1 | Last Updated 17 Jan 2019
Copyright © CodeProject, 1999-2019
All Rights Reserved.
Layout: fixed | fluid