SORU
27 EYLÜL 2010, PAZARTESİ


MVVM ile wpf Diyaloglar için iyi ya da kötü bir uygulama mı?

Ben son zamanlarda wpf uygulamam için ekleme ve düzenleme diyaloglar oluşturma sorunu vardı.

Benim kodda yapmak istediğim böyle bir şeydi. (Ben çoğunlukla mvvm ile viewmodel ilk yaklaşım kullanın)

Bir iletişim penceresi çağıran ViewModel:

 var result = this.uiDialogService.ShowDialog("Dialogwindow title goes here", dialogwindowVM);

 ... do anything with the dialog result...

Nasıl çalışır?

İlk olarak, bir iletişim hizmeti yarattım:

public interface IUIWindowDialogService
{
    bool? ShowDialog(string title, object datacontext);
}

public class WpfUIWindowDialogService : IUIWindowDialogService
{
    public bool? ShowDialog(string title, object datacontext)
    {
        var win = new WindowDialog();
        win.Title = title;
        win.DataContext = datacontext;

        return win.ShowDialog();
    }

}

WindowDialog özel ama basit bir pencere. Benim içerik tutmanı istiyorum:

<Window x:Class="WindowDialog"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    Title="WindowDialog" 
    WindowStyle="SingleBorderWindow" 
    WindowStartupLocation="CenterOwner" SizeToContent="WidthAndHeight">
    <ContentPresenter x:Name="DialogPresenter" Content="{Binding .}">

    </ContentPresenter>
</Window>

Wpf diyaloglar ile ilgili bir sorun dialogresult = true. Bu sadece kod elde edilebilir. Bu benim için bir arayüz dialogviewmodel uygulamak için yarattım.

public class RequestCloseDialogEventArgs : EventArgs
{
    public RequestCloseDialogEventArgs(bool dialogresult)
    {
        this.DialogResult = dialogresult;
    }

    public bool DialogResult
    {
        get; set;
    }
}

public interface IDialogResultVMHelper
{
    event EventHandler<RequestCloseDialogEventArgs> RequestCloseDialog;
}

Benim viewmodel=true dialogresult için her zaman, daha sonra bu olayı başlatmak.

public partial class DialogWindow : Window
{
    //Merken wenn Window geschlossen wurde, damit kein DialogResult mehr gesetzt wird
    private bool _isClosed = false;

    public DialogWindow()
    {
        InitializeComponent();
        this.DialogPresenter.DataContextChanged  = DialogPresenterDataContextChanged;
        this.Closed  = DialogWindowClosed;
    }

    void DialogWindowClosed(object sender, EventArgs e)
    {
        this._isClosed = true;
    }

    private void DialogPresenterDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        var d = e.NewValue as IDialogResultVMHelper;

        if (d == null)
            return;

        d.RequestCloseDialog  = new EventHandler<RequestCloseDialogEventArgs>(DialogResultTrueEvent).MakeWeak(eh => d.RequestCloseDialog -= eh); ;
    }

    private void DialogResultTrueEvent(object sender, RequestCloseDialogEventArgs eventargs)
    {
        //Wichtig damit für ein geschlossenes Window kein DialogResult mehr gesetzt wird
        //GC räumt Window irgendwann weg und durch MakeWeak fliegt es auch beim IDialogResultVMHelper raus
        if(_isClosed) return;

        this.DialogResult = eventargs.DialogResult;
    }

Şimdi en az benim kaynak dosyası DataTemplate (app.xaml veya bir şey) oluşturmak için var:

<DataTemplate DataType="{x:Type DialogViewModel:EditOrNewAuswahlItemVM}" >
        <DialogView:EditOrNewAuswahlItem/>
</DataTemplate>

Evet hepsi bu kadar, şimdi benim viewmodels gelen diyaloglar diyebilirim:

 var result = this.uiDialogService.ShowDialog("Dialogwindow title goes here", dialogwindowVM);

Şimdi benim sorum, bu çözüm ile herhangi bir sorun görüyor musunuz?

Bütünlüğü için. Edit: bu viewmodel İDialogResultVMHelper uygulamak ve bir OkCommand ya da böyle bir şey içinde yükseltebilir

public class MyViewmodel : IDialogResultVMHelper
{
    private readonly Lazy<DelegateCommand> _okCommand;

    public MyViewmodel()
    {
         this._okCommand = new Lazy<DelegateCommand>(() => new DelegateCommand(() => InvokeRequestCloseDialog(new RequestCloseDialogEventArgs(true)), () => YourConditionsGoesHere = true));
    }

    public ICommand OkCommand
    { 
        get { return this._okCommand.Value; } 
    }

    public event EventHandler<RequestCloseDialogEventArgs> RequestCloseDialog;

    private void InvokeRequestCloseDialog(RequestCloseDialogEventArgs e)
    {
        var handler = RequestCloseDialog;
        if (handler != null) 
            handler(this, e);
    }
 }

EDİT 2: benim zayıf Eventhandler kayıt yapmak için http://diditwith.net/2007/03/23/SolvingTheProblemWithEventsWeakEventHandlers.aspx kod kullanın.

public delegate void UnregisterCallback<TE>(EventHandler<TE> eventHandler) 
    where TE : EventArgs;

public interface IWeakEventHandler<TE> 
    where TE : EventArgs
{
    EventHandler<TE> Handler { get; }
}

public class WeakEventHandler<T, TE> : IWeakEventHandler<TE> 
    where T : class 
    where TE : EventArgs
{
    private delegate void OpenEventHandler(T @this, object sender, TE e);

    private readonly WeakReference mTargetRef;
    private readonly OpenEventHandler mOpenHandler;
    private readonly EventHandler<TE> mHandler;
    private UnregisterCallback<TE> mUnregister;

    public WeakEventHandler(EventHandler<TE> eventHandler, UnregisterCallback<TE> unregister)
    {
        mTargetRef = new WeakReference(eventHandler.Target);

        mOpenHandler = (OpenEventHandler)Delegate.CreateDelegate(typeof(OpenEventHandler),null, eventHandler.Method);

        mHandler = Invoke;
        mUnregister = unregister;
    }

    public void Invoke(object sender, TE e)
    {
        T target = (T)mTargetRef.Target;

        if (target != null)
            mOpenHandler.Invoke(target, sender, e);
        else if (mUnregister != null)
        {
            mUnregister(mHandler);
            mUnregister = null;
        }
    }

    public EventHandler<TE> Handler
    {
        get { return mHandler; }
    }

    public static implicit operator EventHandler<TE>(WeakEventHandler<T, TE> weh)
    {
        return weh.mHandler;
    }
}

public static class EventHandlerUtils
{
    public static EventHandler<TE> MakeWeak<TE>(this EventHandler<TE> eventHandler, UnregisterCallback<TE> unregister)
      where TE : EventArgs
    {
        if (eventHandler == null)
            throw new ArgumentNullException("eventHandler");

        if (eventHandler.Method.IsStatic || eventHandler.Target == null)
            throw new ArgumentException("Only instance methods are supported.", "eventHandler");

        var wehType = typeof(WeakEventHandler<,>).MakeGenericType(eventHandler.Method.DeclaringType, typeof(TE));

        var wehConstructor = wehType.GetConstructor(new Type[] { typeof(EventHandler<TE>), typeof(UnregisterCallback<TE>) });

        IWeakEventHandler<TE> weh = (IWeakEventHandler<TE>)wehConstructor.Invoke(new object[] { eventHandler, unregister });

        return weh.Handler;
    }
}

CEVAP
27 EYLÜL 2010, PAZARTESİ


Bu iyi bir yaklaşım olduğunu ve geçmişte benzer olanları kullandım. Onun için git!

Kesinlikle yapardım küçük bir şey, olay "" DialogResult. yanlış ayarlamak için bir boolean almak olun.

event EventHandler<RequestCloseEventArgs> RequestCloseDialog;

ve sınıf EventArgs:

public class RequestCloseEventArgs : EventArgs
{
    public RequestCloseEventArgs(bool dialogResult)
    {
        this.DialogResult = dialogResult;
    }

    public bool DialogResult { get; private set; }
}

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • gsmaestro

    gsmaestro

    17 AĞUSTOS 2006
  • Kindness

    Kindness

    23 Ocak 2006
  • SHAYTARDS

    SHAYTARDS

    1 EKİM 2008