2009-11-06 24 views
15

कैसे एक बटन एक आदेश के लिए एक दृश्य मॉडल में की तरह WPF में MVVM के साथ बाध्य किया जा सकता है में आदेश के लिए बाध्यकारी?WinForms

उत्तर

3

मैंने पहले Button और MenuItem वस्तुओं की Tag संपत्ति को ICommand वस्तुओं संलग्न किया है।

private void button1_Click(object sender, EventArgs e) 
{ 
    ICommand command = ((Control)(sender)).Tag as ICommand; 

    if (command != null) 
    { 
     command.Execute(); 
    } 
} 

भी एक आसान जीवन के लिए, नियंत्रण उपवर्गीकरण (जैसे Button, MenuItem)

0

मुझे नहीं लगता कि आप इसे सीधे कर सकते हैं, लेकिन कैसे आदेश को लागू करने के लिए बटन के क्लिक हैंडलर का उपयोग कर के बारे में? यह डब्ल्यूपीएफ के रूप में साफ नहीं है लेकिन आप अभी भी अपना अलगाव प्राप्त करते हैं।

+0

हाँ, असल में यही वह है जो मैं अब कर रहा हूं - मैं बस सोच रहा था कि बाध्यकारी के साथ ऐसा करने का उचित तरीका है या नहीं। –

0

मैं लागू करने की सलाह देते हैं होता INotifyPropertyChanged आप WPF के साथ ही WinForms में इसका इस्तेमाल कर सकते हैं। कुछ अतिरिक्त जानकारी के लिए here एक परिचय और here देखें।

0

आप का प्रयास करें:

फिर, मैं सिर्फ अगर मैं उदाहरण डाल सकता है और इसे चलाने अगर मैं कर सकते हैं, को देखने के WAF Windows Forms Adapter दिलचस्प हो सकता है। यह दिखाता है कि विंडोज़ फॉर्म एप्लिकेशन में मॉडल-व्यू-व्यू मॉडेल (एमवीवीएम) पैटर्न कैसे लागू करें। एडाप्टर कार्यान्वयन विंडोज फॉर्म में अनुपलब्ध कमांड समर्थन के लिए एक समाधान प्रदान करता है।

13

अगर एक ही बात किया जा सकता है मैं सोच रहा था और एक साधारण CommandManager कि पंजीकृत आदेश (Application.Idle घटना पर) प्रश्नों और डेटा बाइंडिंग का उपयोग करता है लेखन समाप्त नियंत्रण से सक्रिय राज्य

यह वह जगह है बदलने के लिए कोड मैं अभी उपयोग कर रहा हूँ:

public partial class Form1 : Form 
{ 
    private CommandManager commandManager; 

    public ICommand CommandA { get; set; } 
    public ICommand CommandB { get; set; } 

    public bool condition; 

    public Form1() 
    { 
     InitializeComponent(); 

     commandManager = new CommandManager(); 

     CommandA = new DelegateCommand("Command 1", OnTrue, OnExecute); 
     CommandB = new DelegateCommand("Command 2", OnFalse, OnExecute); 

     commandManager.Bind(CommandA, button1); 
     commandManager.Bind(CommandB, button2); 

     commandManager.Bind(CommandA, command1ToolStripMenuItem); 
     commandManager.Bind(CommandB, command2ToolStripMenuItem); 
    } 

    private bool OnFalse() 
    { 
     return !condition; 
    } 

    private bool OnTrue() 
    { 
     return condition; 
    } 

    private void OnExecute() 
    { 
     condition = !condition; 
    } 
} 

इसके अलावा, आप कोड की जरूरत है, मैं blogg:

public class CommandManager: Component 
{ 
    private IList<ICommand> Commands { get; set; } 
    private IList<ICommandBinder> Binders { get; set; } 

    public CommandManager() 
    { 
     Commands = new List<ICommand>(); 

     Binders = new List<ICommandBinder> 
         { 
          new ControlBinder(), 
          new MenuItemCommandBinder() 
         }; 

     Application.Idle += UpdateCommandState; 
    } 

    private void UpdateCommandState(object sender, EventArgs e) 
    { 
     Commands.Do(c => c.Enabled); 
    } 

    public CommandManager Bind(ICommand command, IComponent component) 
    { 
     if (!Commands.Contains(command)) 
      Commands.Add(command); 

     FindBinder(component).Bind(command, component); 
     return this; 
    } 

    protected ICommandBinder FindBinder(IComponent component) 
    { 
     var binder = GetBinderFor(component); 

     if (binder == null) 
      throw new Exception(string.Format("No binding found for component of type {0}", component.GetType().Name)); 

     return binder; 
    } 

    private ICommandBinder GetBinderFor(IComponent component) 
    { 
     var type = component.GetType(); 
     while (type != null) 
     { 
      var binder = Binders.FirstOrDefault(x => x.SourceType == type); 
      if (binder != null) 
       return binder; 

      type = type.BaseType; 
     } 

     return null; 
    } 

    protected override void Dispose(bool disposing) 
    { 
     if (disposing) 
      Application.Idle -= UpdateCommandState; 

     base.Dispose(disposing); 
    } 
} 

public static class Extensions 
{ 
    public static void Do<T>(this IEnumerable<T> @this, Func<T, object> lambda) 
    { 
     foreach (var item in @this) 
      lambda(item); 
    } 
} 
public abstract class CommandBinder<T> : ICommandBinder where T: IComponent 
{ 
    public Type SourceType 
    { 
     get { return typeof (T); } 
    } 

    public void Bind(ICommand command, object source) 
    { 
     Bind(command, (T) source); 
    } 

    protected abstract void Bind(ICommand command, T source); 
} 

public class ControlBinder: CommandBinder<Control> 
{ 
    protected override void Bind(ICommand command, Control source) 
    { 
     source.DataBindings.Add("Enabled", command, "Enabled"); 
     source.DataBindings.Add("Text", command, "Name"); 
     source.Click += (o, e) => command.Execute(); 
    } 
} 

public class MenuItemCommandBinder : CommandBinder<ToolStripItem> 
{ 
    protected override void Bind(ICommand command, ToolStripItem source) 
    { 
     source.Text = command.Name; 
     source.Enabled = command.Enabled; 
     source.Click += (o, e) => command.Execute(); 

     command.PropertyChanged += (o, e) => source.Enabled = command.Enabled; 
    } 
} 

और इस लिए कि यह कैसे उपयोग करने के लिए के एक उदाहरण के है एड के बारे में यह here

+0

आपका समाधान वास्तव में ठीक काम करता है और मेरे संवाद घटकों को और अधिक आसान और समझने योग्य बनाता है :-)। आपका बहुत बहुत धन्यवाद! – rhe1980

+0

खुश है कि यह ठीक काम करता है और आपको यह पसंद है! –

+0

क्या आप समझा सकते हैं कि आप 'DataSindings.Add (..) 'विधि में' DataSourceUpdateMode' 'का उपयोग करने के बजाय' Application.Idle' ईवेंट का उपयोग क्यों करते हैं? –

5

आप एक सामान्य आदेश बाध्यकारी वर्ग एक कमांड किसी भी वर्ग कि ButtonBase से इनहेरिट करने के लिए बाध्य करने की अनुमति देता है कि बना सकते हैं।

public class CommandBinding<T> where T : ButtonBase 
{ 
    private T _invoker; 
    private ICommand _command; 

    public CommandBinding(T invoker, ICommand command) 
    { 
     _invoker = invoker; 
     _command = command; 

     _invoker.Enabled = _command.CanExecute(null); 
     _invoker.Click += delegate { _command.Execute(null); }; 
     _command.CanExecuteChanged += delegate { _invoker.Enabled = _command.CanExecute(null); }; 
    } 
} 

आदेश बाध्यकारी उसके बाद निम्न कोड का उपयोग कर स्थापित किया जा सकता: यदि आप एक शुरुआत देने के लिए तो स्वाभाविक रूप से वहाँ कुछ चेतावनियां हैं

CommandBinding<Button> cmdBinding = 
    new CommandBinding<Button>(btnCut, CutCommand); 

यह वह जगह है सिर्फ अपने कार्यान्वयन के नंगे हड्डियों:

  • उदाहरण मानता WPF ICommand इंटरफ़ेस का उपयोग, इसलिए यदि आप आदेश पैटर्न के अपने खुद के कार्यान्वयन बदला जा करना पड़ सकता है।
  • पैरामीटर में पारित कर रहे हैं अशक्त संदर्भ के लिए जाँच की जानी चाहिए।
  • एक और अधिक ठोस कार्यान्वयन मेमोरी लीक से बचने के लिए घटना हैंडलर निकाल करने के कुछ तरीके होना चाहिए।

सामान्य बाधा भी Control जो Click घटना और Enabled संपत्ति जिसका अर्थ आदेशों लगभग किसी भी नियंत्रण करने के लिए बाध्य किया जा सकता है को उजागर करता है बदला जा सकता है।

1
button1.Click += (s, e) => new MyCommand().Execute(); 
0

जहां मैं Windows फार्म में MVVM का उपयोग कैसे करें आप डिजाइनर का उपयोग कर नियंत्रित करने के लिए आदेश बाध्य करने के लिए चाहते हैं, तो इस डेमो एप्लिकेशन की जाँच करें:

https://bitbucket.org/lbras/mvvmforms

केवल कोड आपके पास कोड-बैक में लिखने के लिए दृश्य मॉडल उदाहरण का निर्माण है।