2013-05-08 3 views
0

Я использую ComboBox в XAML:ComboBox не в состоянии установить DataContext

<ComboBox x:Name="Combobox1" ItemsSource="{Binding}" Margin="0,0,300,0" 
      Width="100" FontSize="30" /> 

в коде позади, я устанавливаю его значение:

protected override void OnNavigatedTo(NavigationEventArgs e) 
{ 
    Combobox1.DataContext = ComponentDataSource.ComponentCollection; 
} 

Теперь у меня есть источник данных:

public class ComponentDataSource 
{  
    private static ObservableCollection<ComponentGroup> _componentcollection;  

    public static ObservableCollection<ComponentGroup> ComponentCollection 
    { 
     get { return _componentcollection; } 
    } 


    public static async void CheckJson(object sender, object e) 
    { 
     var client = new HttpClient(); 
     client.MaxResponseContentBufferSize = 1024 * 1024; 

     try 
     { 
      var response = await client.GetAsync(new Uri("URI")); 
      response.EnsureSuccessStatusCode(); 
      var result = await response.Content.ReadAsStringAsync(); 
      var jobj = JObject.Parse(result); 

      var list = jobj.Children() 
       .Cast<JProperty>() 
       .Select(p => new ComponentGroup() 
       { 
        Name = p.Name, 
        Type = (string)p.Value["P1"], 
        Value = (string)p.Value["P2"] 
       }) 
       .ToList(); 

      _componentcollection = new ObservableCollection<ComponentGroup>(list); 
     } 
     catch (HttpRequestException ex) 
     { 
     } 
    } 
} 

По некоторым причинам эти предметы не отображаются в ComboBox. Все, что я получаю, это пустой ComboBox.

Может ли кто-нибудь помочь мне?

Редактировать 1: Привет, я знаю, что мне не хватает чего-то простого, но если кто-нибудь может мне помочь, я буду очень признателен. BTW, если вы хотите, чтобы код дал мне знать, и я загружу его на skydrive.

+1

Хмм ... все статично в вашей виртуальной машине. Когда вы выполняете привязку в XAML, вы должны установить ItemsSource = {Binding ComponentCollection} (ObservableCollection), а в DataContext вам нужен экземпляр вашего компонента Component Data Source. Но поскольку у него есть статический метод, я не уверен, насколько хорошо он выполнит трюк ... – VasileF

+0

@Vasile Marian Fălămaş, должен ли я сделать какой-либо метод экземпляра метода, а не статический? –

+0

Вежливо отметить лучший/правильный ответ. –

ответ

2

Vasile имеет это прямо в комментариях. XAML в приложениях Windows 8 не может связываться со статическими свойствами. XAML может связываться со стандартными свойствами следующим образом:

public string Name { get; set; } 

Это (выше) будет связываться с equiv. от {Binding Mode=OneTime}. Это потому, что обновления для повышения событий. В то же время вы можете использовать полностью evented свойства, как это:

string m_Name = default(string); 
public string Name { get { return m_Name; } set { SetProperty(ref m_Name, value); } } 

Это будет связывать в XAML, поддерживая любой режим вы указываете (OneTime, OneWay, TwoWay). Это следует за рисунком INotifyPropertyChanged и является довольно простым.

Я говорю все, чтобы сказать это. Эти два подхода - единственный способ привязки. Вы не можете привязываться к полю. Вы не можете привязываться к методу (пока). И вы не можете привязываться к статическому свойству. Если вы должны привязываться к статическому свойству, просто выставьте свое статическое свойство в стандартном свойстве в вашей модели просмотра.

Чтобы показать вам, что я говорю правду, рассмотреть этот код XAML (почти как у вас):

<ComboBox x:Name="MyCombo" ItemsSource="{Binding}" /> 

Если вы попытаетесь это сделать, он будет связывать штраф:

protected override void OnNavigatedTo(NavigationEventArgs e) 
{ 
    this.MyCombo.DataContext = new MyModel().Items; 
    base.OnNavigatedTo(e); 
} 

public class MyModel 
{ 
    public MyModel() 
    { 
     foreach (var item in Enumerable.Range(1, 50)) 
      Items.Add(item); 
    } 
    ObservableCollection<int> m_Items = new ObservableCollection<int>(); 
    public ObservableCollection<int> Items { get { return m_Items; } } 
} 

Единственное различие между две части - static. Так что даже нажатие значений так, как вы пытаетесь, не будет работать. Это потому, что вы привязываетесь непосредственно к статическому свойству.

Вот способ иметь staticи подвергать его таким образом он будет связываться:

protected override void OnNavigatedTo(NavigationEventArgs e) 
{ 
    this.MyCombo.DataContext = new MyModel().Items; 
    base.OnNavigatedTo(e); 
} 

public class MyModel 
{ 
    public MyModel() 
    { 
     foreach (var item in Enumerable.Range(1, 50)) 
      s_Items.Add(item); 
    } 
    private static ObservableCollection<int> s_Items = new ObservableCollection<int>(); 
    public ObservableCollection<int> Items { get { return s_Items; } } 
} 

В приведенной выше коде, у меня есть значение статического в MyModel классе, но у меня есть стандартное свойство разоблачения его , Поскольку это ObservableColelction, свойство уже имеет значение для привязки, поэтому это может быть полная реализация. Таким образом, вы получаете staticи переплет. Имеют смысл?

Теперь к смущающей части.

Техника, которую вы используете для привязки в своем вопросе, должна работать. Связывание статического свойства с DataContext, а затем привязка к нему в ItemsSource произведениях. @ maad0 продемонстрировал, что это прекрасный подход. Итак, почему он не работает для вас.

Я полагаю, что все, что я могу сказать, это «Это не потому, что вы неправы». <blush /> У меня возникло соблазн удалить мой ответ, но я оставляю его только потому, что объяснение статической привязки может быть ценным для разработчиков, которые пытаются это сделать.

Проверьте свой код с этим

Это ваш метод CheckJson. Я добавил заявление отладчика, чтобы увидеть, действительно ли вы получаете какие-либо результаты. Попробуйте использовать этот образец в своем приложении и посмотрите, не сломается ли он. Если он не сломается, проблема заключается не в том, что у вас нет данных. Проблема как-то в вашей привязке. Хотя все выглядит хорошо для меня.

public static async void CheckJson(object sender, object e) 
{ 
    var client = new HttpClient(); 
    client.MaxResponseContentBufferSize = 1024 * 1024; 

    try 
    { 
     var response = await client.GetAsync(new Uri("URI")); 
     response.EnsureSuccessStatusCode(); 
     var result = await response.Content.ReadAsStringAsync(); 
     var jobj = JObject.Parse(result); 

     var list = jobj.Children() 
      .Cast<JProperty>() 
      .Select(p => new ComponentGroup() 
      { 
       Name = p.Name, 
       Type = (string)p.Value["P1"], 
       Value = (string)p.Value["P2"] 
      }) 
      .ToList(); 

     // add this code 
     if (!_componentcollection.Any()) 
      System.Diagnostics.Debugger.Break(); 

     _componentcollection = new ObservableCollection<ComponentGroup>(list); 
    } 
    catch (HttpRequestException ex) 
    { 
    } 
} 
+1

За исключением того, что он не является обязательным для статического свойства, он привязывается к его «DataContext». Тот факт, что значение, хранящееся в 'DataContext', происходит от статического свойства, также не является проблемой. Проблема в том, что он заменяет это значение каждый раз, когда он называет 'CheckJson', но механизм привязки не знает об этом. – madd0

+1

Привязка к статическому свойству или привязка к DataContext, который ссылается на то же значение, что и статическое свойство, не одно и то же. Он делает последнее, и он работает. Я могу отправить вам пример приложения, который докажет это, если хотите. – madd0

+0

Вы правы. 100%. Спасибо, что нашли время, чтобы показать мне. Мой тестовый проект был неточным в отношении привязки «DataContext». Чтобы быть ясным, вы можете привязать статическое свойство к «DataContext», а затем привязать «ItemsSource» к «DataContext». Это работает, хотя для его завершения требуется код. Вы не можете привязываться к статическому свойству исключительно из XAML. Я обновил свой ответ, чтобы отразить это. –

2

Есть несколько вещей в вашем коде, которые могут привести к пустой ComboBox:

  • Ваш веб-сервис на самом деле возвращающимся результаты? Это исключение, которое вы глотаете, может скрыть тот факт, что вы фактически работаете с пустым (или null) списком. Сейчас это не ваша проблема, но может быть.

  • Предполагая, что ваша коллекция имеет элементы, и поскольку вы используете код позади, почему бы вам просто не назначить свойство ItemsSource?

    protected override void OnNavigatedTo(NavigationEventArgs e) 
    { 
        Combobox1.ItemsSource = ComponentDataSource.ComponentCollection; 
    } 
    

    Это покажет ваши товары, если ваша коллекция не пуста.

Несмотря на то, что другие считают, ваше связывание является правильным, так как вы не привязкой к статическому свойству. Вы привязываетесь к объекту, DataContext, и вы устанавливаете его как значение статического свойства. Если ваша коллекция не null и имеет значения до, вы назначаете ее в свой поле со списком DataContext, после чего элементы будут отображаться.

Я полагаю, что в вашем случае происходит то, что вы устанавливаете DataContext либо в значение null, либо в лучшем случае в пустую коллекцию.

Ваш метод CheckJson очень похож на обработчик событий для DispatchTimer, поэтому я предполагаю, что вы регулярно загружаете элементы из Интернета, чтобы отображать их в своем поле со списком. Однако обратите внимание, что каждый раз, когда вы это делаете, вы заменяете коллекцию, содержащую их, с новым ObservableCollection!

Чтобы проверить мои два предположения, все, что вам нужно сделать, это позвонить CheckJson (и убедиться, что он полностью запущен), прежде чем назначить DataContext.

Самый простой способ исправить вашу проблему, тем более, что ваша коллекция является статическим, чтобы хранить ObservableCollection один раз в _componentcollection (например, в статическом конструкторе класса или его инициализации, когда он объявлен), а затем просто Add, Remove , или Clear элементов по мере необходимости. Поскольку ваш поле со списком всегда будет прослушивать один и тот же список, он будет уведомлен, когда его содержимое изменится. Вы бы:

private static ObservableCollection<ComponentGroup> _componentcollection = new ObservableCollection<ComponentGroup>(); 

И в CheckJson, заменить:

_componentcollection = new ObservableCollection<ComponentGroup>(list); 

с:

_componentcollection.Clear(); 

foreach (var item in list) 
{ 
    _componentcollection.Add(item); 
} 

PS. Мое предложение, приведенное выше, напрямую использовать ItemsSource, будет страдать от той же проблемы, что и текущий код, он просто берет привязку из изображения и доказывает, что привязка не является проблемой. Вы все равно должны быть осторожны, чтобы не заменить список в статическом коде, например, используя один ObservableCollection, как я предлагаю в конце моего ответа.

+0

Я согласен, что это не его привязка. Спасибо за примечание. –

Смежные вопросы