Основная проблема в вашем коде заключается в том, что System.Windows.Media.SolidColorBrush
не переопределяет метод Equals()
, и поэтому ваше выражение Background == Brushes.Black
никогда не будет true
. Так как вы создаете явные новые экземпляры объекта SolidColorBrush
, а оператор ==
просто сравнивает ссылки на экземпляры, сравнение между значением кисти и встроенным экземпляром Brushes.Black
всегда терпит неудачу.
Самый простой способ исправить код - это просто использовать фактические Brushes
экземпляры:
private void Timer_Tick(object sender, System.EventArgs e)
{
if (Background == Brushes.Black)
{
Background = Brushes.White;
Title = "White";
}
else
{
Background = Brushes.Black;
Title = "Black";
}
}
Затем, когда вы сравниваете ссылки на экземпляры, они на самом деле сравнимы, и вы обнаружите «черное» состояние по желанию.
Я отмечу, что, поскольку вы также не повышаете значение PropertyChanged
для изменения свойства Title
, эта привязка также не будет работать должным образом.
1128 За то, что оно того стоит, я бы вообще избежал вашего замысла. Во-первых, при просмотре объектов модели следует избегать использования специфичных для пользовательского интерфейса типов. Конечно, это будет включать тип Brush
. Возможно, это также включает в себя DispatcherTimer
, так как он существует в обслуживании UI. Помимо этого, DispatcherTimer
является относительно неточным таймером, и, хотя он существует, главным образом, для того, чтобы иметь таймер, который вызывает его событие Tick
в потоке диспетчера, которому принадлежит таймер, поскольку WPF автоматически собирает события изменения свойств из любого другого потока в поток пользовательского интерфейса, он не так полезен в этом примере.
Вот версия вашей программы, которая IMHO больше соответствует типичным практикам программирования WPF:
class MainViewModel : NotifyPropertyChangedBase
{
private string _title;
public string Title
{
get { return _title; }
set { _UpdateField(ref _title, value); }
}
private bool _isBlack;
public bool IsBlack
{
get { return _isBlack; }
set { _UpdateField(ref _isBlack, value, _OnIsBlackChanged); }
}
private void _OnIsBlackChanged(bool obj)
{
Title = IsBlack ? "Black" : "White";
}
public MainViewModel()
{
IsBlack = true;
_ToggleIsBlack(); // fire and forget
}
private async void _ToggleIsBlack()
{
while (true)
{
await Task.Delay(TimeSpan.FromMilliseconds(100));
IsBlack = !IsBlack;
}
}
}
Этот класс модели представления использует базовый класс, который я использую для всех моих моделей представления, поэтому я не нужно переопределять INotifyPropertyChanged
все время:
class NotifyPropertyChangedBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void _UpdateField(ref T field, T newValue,
Action onChangedCallback = null,
[CallerMemberName] string propertyName = null)
{
if (EqualityComparer.Default.Equals(field, newValue))
{
return;
}
T oldValue = field;
field = newValue;
onChangedCallback?.Invoke(oldValue);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Вы заметите, что класс модели представления не имеет никакого поведения, специфичного для пользовательского интерфейса. Он будет работать с любой программой, WPF или другой, при условии, что эта программа способна реагировать на события PropertyChanged
и использовать значения в модели представления.
Чтобы сделать эту работу, XAML становится несколько более многословным:
(Примечание: я явно назвал http://schemas.microsoft.com/netfx/2007/xaml / presentation Пространство имен XML для использования с элементом исключительно в качестве обходного пути для недостаточной обработки разметки XML в Stack Overflow, которая иначе не распознала бы элемент
как фактический элемент XML. Программу, вы можете не стеснять этого.)
Ключевым моментом здесь является то, что вся обработка проблемы пользовательского интерфейса находится в самой декларации пользовательского интерфейса. Модель представления не должна знать, как пользовательский интерфейс представляет черный или белый цвета. Это просто переключает флаг. Затем пользовательский интерфейс отслеживает этот флаг и применяет установщики свойств в соответствии с его текущим значением.
Наконец, я отмечу, что для многократного изменения состояния в пользовательском интерфейсе, подобного этому, другой подход заключается в использовании анимационных функций WPF. Это выходит за рамки этого ответа, но я призываю вас прочитать об этом. Одним из преимуществ этого является то, что анимация использует модель синхронизации с еще более высоким разрешением, чем метод, основанный на пуле потоков Task.Delay()
, который я использовал выше, и поэтому обычно обеспечивает еще более плавную анимацию (хотя, конечно, поскольку ваш интервал становится меньше и меньше & mdash; например, 25 мс, поскольку ваше сообщение указывает на то, что вы намеревались использовать & mdash; у вас возникнут проблемы с плавным поддержанием WPF независимо от того, в какой-то момент вы обнаружите, что высокоуровневые инфраструктуры пользовательского интерфейса, такие как WinForms, WPF, Xamarin, и т.д. просто не может работать на таком мелкозернистом уровне таймера).
Я думаю, что webob может добиться цели, видеть конец примера файла для реализации запроса диапазона, которая эффективно ищет в подаваемый файл.
Вам просто нужно использовать WebOb и создать ответ как Response (conditional_request = True)
или подкласс объекта WebOb Response , создавая conditional_request = True
по умолчанию.
Когда conditional_request = True
и запрос запрашивает диапазон, WebOb Response.app_iter_range
завершает полный ответ, возвращая только запрошенный диапазон.
В примере обслуживания файла WebOb показано, как реализовать собственное app_iter_range
для случаев, когда целесообразно получить диапазон байтов без генерации всего ответа.