2008-09-17 27 views
15

जब भी व्यूमोडेल/प्रेजेंटेशन मॉडल व्यस्त होता है तो मैं एक प्रगति एनीमेशन ट्रिगर करने की कोशिश कर रहा हूं। मेरे पास IsBusy प्रॉपर्टी है, और ViewModel को UserControl के DataContext के रूप में सेट किया गया है। IsBusy संपत्ति सत्य होने पर "प्रगति एनीमेशन" कहानी बोर्ड को ट्रिगर करने का सबसे अच्छा तरीका क्या है? मिश्रण केवल उपयोगकर्ता नियंत्रण स्तर पर इवेंट-ट्रिगर्स जोड़ने दें, और मैं केवल अपने डेटा टेम्पलेट्स में संपत्ति ट्रिगर्स बना सकता हूं।डब्ल्यूपीएफ डेटा ट्रिगर्स और स्टोरी बोर्ड

"प्रगतिएनीमेशन" को उपयोगकर्ता नियंत्रण में संसाधन के रूप में परिभाषित किया गया है।

मैं UserControl पर एक शैली के रूप में DataTriggers जोड़ने की कोशिश की, लेकिन जब मैं स्टोरीबोर्ड मैं निम्नलिखित त्रुटि मिलती प्रारंभ करने का प्रयास:

'System.Windows.Style' value cannot be assigned to property 'Style' 
of object'Colorful.Control.SearchPanel'. A Storyboard tree in a Style 
cannot specify a TargetName. Remove TargetName 'progressWheel'. 

ProgressWheel वस्तु मैं चेतन करने के लिए कोशिश कर रहा हूँ का नाम है , इसलिए लक्ष्य नाम को हटा देना obvisouly नहीं है जो मैं चाहता हूं।

मैं घटनाओं का पर्दाफाश करने और कोड के माध्यम से एनीमेशन को शुरू/बंद करने के मामले में डेटा बाइंडिंग तकनीकों का उपयोग करके एक्सएएमएल में इसे हल करने की उम्मीद कर रहा था।

उत्तर

29

क्या आप चाहते हैं progressWheel पर ही एनीमेशन की घोषणा के द्वारा संभव है: XAML :

<UserControl x:Class="TriggerSpike.UserControl1" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
Height="300" Width="300"> 
<UserControl.Resources> 
    <DoubleAnimation x:Key="SearchAnimation" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:4"/> 
    <DoubleAnimation x:Key="StopSearchAnimation" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:4"/> 
</UserControl.Resources> 
<StackPanel> 
    <TextBlock Name="progressWheel" TextAlignment="Center" Opacity="0"> 
     <TextBlock.Style> 
      <Style> 
       <Style.Triggers> 
        <DataTrigger Binding="{Binding IsBusy}" Value="True"> 
         <DataTrigger.EnterActions> 
          <BeginStoryboard> 
           <Storyboard> 
            <StaticResource ResourceKey="SearchAnimation"/> 
           </Storyboard> 
          </BeginStoryboard> 
         </DataTrigger.EnterActions> 
         <DataTrigger.ExitActions> 
          <BeginStoryboard> 
           <Storyboard> 
            <StaticResource ResourceKey="StopSearchAnimation"/> 
           </Storyboard> 
          </BeginStoryboard> 
         </DataTrigger.ExitActions> 
        </DataTrigger> 
       </Style.Triggers> 
      </Style> 
     </TextBlock.Style> 
     Searching 
    </TextBlock> 
    <Label Content="Here your search query"/> 
    <TextBox Text="{Binding SearchClause}"/> 
    <Button Click="Button_Click">Search!</Button> 
    <TextBlock Text="{Binding Result}"/> 
</StackPanel> 

पीछे कोड:

using System.Windows; 
using System.Windows.Controls; 

namespace TriggerSpike 
{ 
    public partial class UserControl1 : UserControl 
    { 
     private MyViewModel myModel; 

     public UserControl1() 
     { 
      myModel=new MyViewModel(); 
      DataContext = myModel; 
      InitializeComponent(); 
     } 

     private void Button_Click(object sender, RoutedEventArgs e) 
     { 
      myModel.Search(myModel.SearchClause); 
     } 
    } 
} 

viewmodel:

using System.ComponentModel; 
using System.Threading; 
using System.Windows; 

namespace TriggerSpike 
{ 
    class MyViewModel:DependencyObject 
    { 

     public string SearchClause{ get;set;} 

     public bool IsBusy 
     { 
      get { return (bool)GetValue(IsBusyProperty); } 
      set { SetValue(IsBusyProperty, value); } 
     } 

     public static readonly DependencyProperty IsBusyProperty = 
      DependencyProperty.Register("IsBusy", typeof(bool), typeof(MyViewModel), new UIPropertyMetadata(false)); 



     public string Result 
     { 
      get { return (string)GetValue(ResultProperty); } 
      set { SetValue(ResultProperty, value); } 
     } 

     public static readonly DependencyProperty ResultProperty = 
      DependencyProperty.Register("Result", typeof(string), typeof(MyViewModel), new UIPropertyMetadata(string.Empty)); 

     public void Search(string search_clause) 
     { 
      Result = string.Empty; 
      SearchClause = search_clause; 
      var worker = new BackgroundWorker(); 
      worker.DoWork += worker_DoWork; 
      worker.RunWorkerCompleted += worker_RunWorkerCompleted; 
      IsBusy = true; 
      worker.RunWorkerAsync(); 
     } 

     void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
      IsBusy=false; 
      Result = "Sorry, no results found for: " + SearchClause; 
     } 

     void worker_DoWork(object sender, DoWorkEventArgs e) 
     { 
      Thread.Sleep(5000); 
     } 
    } 
} 

आशा है कि इससे मदद मिलती है!

1

मैं आपकी IsBusy संपत्ति के बजाय RoutedEvent का उपयोग करने की अनुशंसा करता हूं। बस OnBusyStarted और OnBusyStopped ईवेंट आग और उपयुक्त तत्वों पर घटना ट्रिगर का उपयोग करें।

+1

ठीक है, यही वह था जो मैं उम्मीद कर रहा था इससे बचें ... लेकिन, मैं यह करता हूं: एक वर्ग में रूटेडएवेंट को कार्यान्वित करने के तरीके पर कोई उदाहरण जो UIElement से प्राप्त नहीं होता है? –

1

आप डेटाऑब्जेक्ट क्लास की प्रॉपर्टी चेंजेड इवेंट की सदस्यता ले सकते हैं और उपयोगकर्ता नियंत्रण स्तर से रूटेड इवेंट आग बना सकते हैं।

RoutedEvent के लिए काम करने के लिए हम वर्ग DependancyObject

+0

मुझे लगता है कि आप सही हैं ... उपयोगकर्ता नियंत्रण केंद्र से रूटरएड को सबसे स्पष्ट समाधान की तरह एक्सपोज़ करना ... हालांकि, मैंने अभी तक डेटा के आधार पर मनमाने ढंग से स्टोरीबोर्ड निष्पादित करने पर छोड़ दिया नहीं है .. लेकिन इनपुट के लिए धन्यवाद! –

0

आप Trigger.EnterAction उपयोग कर सकते हैं एक एनीमेशन शुरू करने के लिए जब एक संपत्ति बदल गया है से प्राप्त की आवश्यकता है।

<Trigger Property="IsBusy" Value="true"> 
    <Trigger.EnterActions> 
     <BeginStoryboard x:Name="BeginBusy" Storyboard="{StaticResource MyStoryboard}" /> 
    </Trigger.EnterActions> 
    <Trigger.ExitActions> 
     <StopStoryboard BeginStoryboardName="BeginBusy" /> 
    </Trigger.ExitActions> 
</Trigger> 
+0

जैसा मैंने कहा, यह उपयोगकर्ता नियंत्रण स्तर पर है, और मैं केवल EventTriggers स्वीकार करता हूं (संपत्ति- या DataTriggers नहीं)। साथ ही, IsBusy UserControl पर एक प्रॉपर्टी नहीं है, लेकिन ऑब्जेक्ट पर DataContext (ViewModel) के रूप में सेट है –

4

हालांकि उत्तर जो एनीमेशन को सीधे एनिमेटेड करने के लिए एनीमेशन को जोड़ने का प्रस्ताव करता है, यह समस्या सरल मामलों में हल करती है, यह वास्तव में व्यावहारिक नहीं है जब आपके पास एक जटिल एनीमेशन है जिसे एकाधिक तत्वों को लक्षित करने की आवश्यकता होती है। (आप निश्चित रूप से प्रत्येक तत्व के लिए एक एनीमेशन संलग्न कर सकते हैं, लेकिन यह प्रबंधन के लिए बहुत भयानक हो जाता है।)

तो इसका समाधान करने का एक वैकल्पिक तरीका है जो आपको DataTrigger का उपयोग करने वाले एनीमेशन को चलाने के लिए उपयोग करता है जो तत्वों को लक्षित करता है।

ऐसे तीन स्थान हैं जहां आप WPF में तत्वों को जोड़ सकते हैं: तत्व, शैलियों और टेम्पलेट्स। हालांकि, पहले दो विकल्प यहां काम नहीं करते हैं। पहले को अस्वीकार कर दिया गया है क्योंकि डब्ल्यूपीएफ सीधे किसी तत्व पर DataTrigger के उपयोग का समर्थन नहीं करता है। (जहां तक ​​मुझे पता है, इसके लिए कोई विशेष कारण नहीं है। जहां तक ​​मुझे याद है, जब मैंने कई वर्षों पहले डब्ल्यूपीएफ टीम पर लोगों से पूछा, तो उन्होंने कहा कि उन्हें इसका समर्थन करना अच्छा लगेगा लेकिन नहीं इसे काम करने के लिए समय है।) और शैलियों को बाहर कर दिया गया है, क्योंकि आपके द्वारा रिपोर्ट की गई त्रुटि संदेश कहता है, आप शैली से जुड़े एनीमेशन में नामित तत्वों को लक्षित नहीं कर सकते हैं।

तो टेम्पलेट छोड़ देता है। और आप इसके लिए या तो नियंत्रण या डेटा टेम्पलेट का उपयोग कर सकते हैं।

<ContentControl> 
    <ContentControl.Template> 
     <ControlTemplate TargetType="ContentControl"> 
      <ControlTemplate.Resources> 
       <Storyboard x:Key="myAnimation"> 

        <!-- Your animation goes here... --> 

       </Storyboard> 
      </ControlTemplate.Resources> 
      <ControlTemplate.Triggers> 
       <DataTrigger 
        Binding="{Binding MyProperty}" 
        Value="DesiredValue"> 
        <DataTrigger.EnterActions> 
         <BeginStoryboard 
          x:Name="beginAnimation" 
          Storyboard="{StaticResource myAnimation}" /> 
        </DataTrigger.EnterActions> 
        <DataTrigger.ExitActions> 
         <StopStoryboard 
          BeginStoryboardName="beginAnimation" /> 
        </DataTrigger.ExitActions> 
       </DataTrigger> 
      </ControlTemplate.Triggers> 

      <!-- Content to be animated goes here --> 

     </ControlTemplate> 
    </ContentControl.Template> 
<ContentControl> 

इस निर्माण के साथ, WPF करने के लिए एनीमेशन टेम्पलेट के अंदर नामित तत्वों का उल्लेख करते हैं खुश है। (मैंने एनीमेशन और टेम्पलेट सामग्री दोनों को खाली छोड़ दिया है - जाहिर है कि आप अपनी वास्तविक एनीमेशन एनडी सामग्री के साथ इसे पॉप्युलेट करेंगे।)

कारण यह टेम्पलेट में काम करता है लेकिन शैली नहीं है कि जब आप एक आवेदन करते हैं टेम्पलेट, परिभाषित किए गए नामित तत्व हमेशा मौजूद होंगे, और इसलिए उन तत्वों के संदर्भ में उस टेम्पलेट के दायरे में परिभाषित एनिमेशन के लिए यह सुरक्षित है। यह आम तौर पर शैली के साथ मामला नहीं है, क्योंकि शैलियों को कई अलग-अलग तत्वों पर लागू किया जा सकता है, जिनमें से प्रत्येक में अलग-अलग दृश्य पेड़ हो सकते हैं। (यह थोड़ा निराशाजनक है कि यह आपको परिदृश्यों में भी ऐसा करने से रोकता है जब आप निश्चित हो सकते हैं कि आवश्यक तत्व वहां होंगे, लेकिन शायद ऐसा कुछ है जो एनीमेशन के लिए नामित तत्वों के लिए बाध्य होना बहुत कठिन बनाता है समय। मुझे पता है कि शैली के तत्वों को कुशलतापूर्वक पुन: उपयोग करने के लिए WPF में बहुत सारे अनुकूलन हैं, इसलिए शायद उनमें से एक यह है कि इसका समर्थन करना मुश्किल हो जाता है।)

संबंधित मुद्दे