Click here to Skip to main content
15,868,016 members
Home / Discussions / WPF
   

WPF

 
QuestionAd Control / monetization Pin
Super Lloyd18-Dec-18 13:02
Super Lloyd18-Dec-18 13:02 
AnswerRe: Ad Control / monetization Pin
Pete O'Hanlon18-Dec-18 22:17
subeditorPete O'Hanlon18-Dec-18 22:17 
GeneralRe: Ad Control / monetization Pin
Super Lloyd19-Dec-18 15:40
Super Lloyd19-Dec-18 15:40 
AnswerRe: Ad Control / monetization Pin
Gerry Schmitz23-Dec-18 9:02
mveGerry Schmitz23-Dec-18 9:02 
GeneralRe: Ad Control / monetization Pin
Super Lloyd23-Dec-18 9:39
Super Lloyd23-Dec-18 9:39 
GeneralRe: Ad Control / monetization Pin
Gerry Schmitz28-Dec-18 9:39
mveGerry Schmitz28-Dec-18 9:39 
QuestionValidation in WPF Pin
Kevin Marois18-Dec-18 6:59
professionalKevin Marois18-Dec-18 6:59 
AnswerRe: Validation in WPF Pin
Super Lloyd18-Dec-18 13:09
Super Lloyd18-Dec-18 13: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!

AnswerRe: Validation in WPF Pin
Gerry Schmitz23-Dec-18 8:57
mveGerry Schmitz23-Dec-18 8:57 
QuestionI dont now what is the error "{"An ItemsControl is inconsistent with its items source.\n See the inner exception for more information."}" Pin
Rabee3-F1.78754516-Dec-18 2:01
Rabee3-F1.78754516-Dec-18 2:01 
AnswerRe: I dont now what is the error "{"An ItemsControl is inconsistent with its items source.\n See the inner exception for more information."}" Pin
Super Lloyd16-Dec-18 15:50
Super Lloyd16-Dec-18 15:50 
GeneralRe: I dont now what is the error "{"An ItemsControl is inconsistent with its items source.\n See the inner exception for more information."}" Pin
Rabee3-F1.78754517-Dec-18 10:22
Rabee3-F1.78754517-Dec-18 10:22 
GeneralRe: I dont now what is the error "{"An ItemsControl is inconsistent with its items source.\n See the inner exception for more information."}" Pin
Super Lloyd17-Dec-18 15:28
Super Lloyd17-Dec-18 15:28 
AnswerRe: I dont now what is the error "{"An ItemsControl is inconsistent with its items source.\n See the inner exception for more information."}" Pin
Richard Deeming17-Dec-18 9:20
mveRichard Deeming17-Dec-18 9:20 
QuestionI dont now what is the error "{"An ItemsControl is inconsistent with its items source.\n See the inner exception for more information."}" Pin
Rabee3-F1.78754516-Dec-18 1:34
Rabee3-F1.78754516-Dec-18 1:34 
QuestionReorder Elements in ScrollViewer/Grid Pin
GenJerDan12-Dec-18 9:38
GenJerDan12-Dec-18 9:38 
AnswerRe: Reorder Elements in ScrollViewer/Grid Pin
Super Lloyd12-Dec-18 18:11
Super Lloyd12-Dec-18 18:11 
GeneralRe: Reorder Elements in ScrollViewer/Grid Pin
GenJerDan12-Dec-18 19:27
GenJerDan12-Dec-18 19:27 
QuestionBorder With Bound Pulsating Color Pin
Kevin Marois10-Dec-18 5:53
professionalKevin Marois10-Dec-18 5:53 
AnswerRe: Border With Bound Pulsating Color Pin
Super Lloyd12-Dec-18 17:06
Super Lloyd12-Dec-18 17:06 
QuestionBinding To Single List Item Pin
Kevin Marois27-Nov-18 10:23
professionalKevin Marois27-Nov-18 10:23 
AnswerRe: Binding To Single List Item Pin
Meshack Musundi27-Nov-18 20:17
professionalMeshack Musundi27-Nov-18 20:17 
GeneralRe: Binding To Single List Item Pin
Pete O'Hanlon27-Nov-18 21:03
subeditorPete O'Hanlon27-Nov-18 21:03 
GeneralRe: Binding To Single List Item Pin
Meshack Musundi27-Nov-18 21:12
professionalMeshack Musundi27-Nov-18 21:12 
GeneralRe: Binding To Single List Item Pin
Pete O'Hanlon27-Nov-18 22:19
subeditorPete O'Hanlon27-Nov-18 22:19 

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.