понедельник, 7 ноября 2011 г.

WPF: ComboBox с прогресс баром

Необходимо было создать комбобокс, который показывал бы прогресс при асинхронной загрузке данных с сервиса. Получилось примерно следующее:

<Style TargetType="ComboBox" BasedOn="{StaticResource {x:Type ComboBox}}" x:Key="ProgressComboBox">
    <Style.Triggers>
      <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=ItemsSource}" Value="{x:Null}">
        <Setter Property="Template">
          <Setter.Value>
            <ControlTemplate TargetType="ComboBox">
              <Grid>
                <ComboBox />
                <с:GifImage Gif="pack://application:,,,/Images/loader16.gif" Stretch="None" Width="16" Height="16" Margin="10,2,2,2" HorizontalAlignment="Left" />
              </Grid>
            </ControlTemplate>
          </Setter.Value>
        </Setter>
      </DataTrigger>
    </Style.Triggers>
  </Style>


* This source code was highlighted with Source Code Highlighter.

GifImage позаимствован отсюда. Главное - не забывать сделать Binding асинхронным:
<ComboBox ItemsSource="{Binding MyCollection, IsAsync=True}" Style="{StaticResource ProgressComboBox}" />

вторник, 1 июня 2010 г.

Директивы ASP.NET Pages

На сайте GotDotNet натолкнулся на интересную статью. Был прятно удивлен, что оказывается можно в странице указать какая именно мастер пейдж используется и как следствие, получить доступ к её свойствам. А я делал приведение типов...

вторник, 22 сентября 2009 г.

Любимые extension methods

Расширения для событий:

static void Fire<T>(this EventHandler<T> handler, object sender, T eventArgs) where T : System.EventArgs
{
     if (handler != null)
          handler(sender, eventArgs);
}
public static void Fire(this EventHandler handler, object sender, System.EventArgs eventArgs)
{
     if (handler != null)
          handler(sender, eventArgs);
}

Расширения для коллекций:

public static bool IsEmpty<T>(this ICollection<T> list)
{
     return list == null || list.Count == 0;
}
public static void Foreach<T>(this IEnumerable<T> collection, Action<T> action)
{
     if (collection != null)
          foreach (var item in collection)
               action(item);
}

Расширения для строк:

public static int ToInt(this string value)
{
     int i;
     int.TryParse(value, out i);
     return i;
}
public static bool IsEmpty(this string value)
{
     return string.IsNullOrEmpty(value);
}
public static bool PoorEquals(this string value, string value2)
{
     return value != null && value2 != null 
            && value.Equals(value2, 
                 StringComparison.InvariantCultureIgnoreCase);
}

понедельник, 21 сентября 2009 г.

.NET 3.5: Quick start или как раскрутить директора.

- Посмотрел документы.
- Нужно написать эту систему. Наша часть - только юай + контроллеры. База - на каше в Америке. Сервисы нам будут предоставлены.
- Как на счёт использования .NET 3.5?
- А зачем он вам? Entity framework все равно использоваться не будет.


Именно с этого диалога я начну рассказ о том, какую пользу принесет использование .NET 3.5 в проектах без использования Entity Framework.

Пример номер раз (методы-расширения):

Как часто приходится писать подобный код:
string value = Request.Params["VacancyID"];
int id;
int.TryParse(value, out id);
ViewCandidate(id);
Было бы здорово, если бы у строки был метод, преобразующий её в число. Например такой:
value.ToInt()
.NET 3.5 дает такую возможность. Достаточно в каком-либо классе объявить следующий статический метод:
public static int ToInt(this string value)
{
int id;
int.TryParse(value, out id);
return id;
}
Теперь можно писать так:
string value = Request.Params["VacancyID"];
ViewCandidate(value.ToInt());
Ключевое слово this перед параметром указывает, что этот метод является расширением для типа параметра. Теперь у всех объектов типа String, «появляется» метод ToInt().
Примеры удобных расширений:
public static bool IsEmpty<T>(this IEnumerable<T> list)
{
return list == null || list.Count() == 0;
}
public static void Fire<TEventArgs>(this EventHandler<TEventArgs> eventHandler, object sender, TEventArgs e) where TEventArgs : System.EventArgs
{
if (eventHandler != null)
eventHandler(sender, e);
}

Пример номер два (неявно типизированные переменные):

Подобный код встречается реже, но тоже бывает:
IDictionary<CandidateFilter, IList<CandidateState>> cf = new Dictionary<CandidateFilter, IList<CandidateState>>()
Бррр... С помощью .NET 3.5 это можно записать вот так:
var cf = new Dictionary<CandidateFilter, IList<CandidateState>>()


Тип переменной определяется из устанавливаемого значения, поэтому нельзя написать следующее:
var i;
var k = null;

Пример номер три (анонимные типы):

Иногда появляется необходимость создать временный класс, сущность которого сводится только к набору полей. С появлением неявного типизирования, появилась возможность добавить анонимные типы - типы, для которых классы создаются в процессе выполнения программы. Теперь можно написать вот так:
var c = new { User = currentUser, DateTime = DateTime.Now };
Console.WriteLine(c.DateTime);
Console.WriteLine(c.User.Name);

Пример номер четыре (авто свойства):

В классах доменой модели часто можно встретить подобный код:
class User
{
private string _firstName;
private string _lastName;

public string FirstName
{
get { return _firstName; }
set { _firstName = value; }
}
public string LastName
{
get { return _lastName; }
set { _lastName = value; }
}
}
Теперь его можно упростить:
class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
}

Пример номер шесть (лямбда выражения):

В библиотеке System.Core объявлены следующие универсальные делегаты:
public delegate TResult Func<T1 arg1, T2 arg2, T3 arg3, T4 arg4>;
public delegate TResult Func<T1 arg1, T2 arg2, T3 arg3>;
public delegate TResult Func<T1 arg1, T2 arg2>;
public delegate TResult Func<T1 arg1>;
Они подходят практически для любых функций и процедур.
Пусть в приложении необходимо использование следующего выражения:
Func<CandidateState, int> func = delegate(CandidateState state)
{
return (int)state;
};
С помощью лямбда выражений его можно заменить на:
Func<CandidateState, int> func = state => (int) state;
В данном случае state до знака => - это объявление параметра метода, а (int)state это то, что вставится после return.
При необходимости можно использовать и несколько параметров:
Func<int,int,int> f = (x, y) => x + y;
С использованием лямбда выражений проверка на существование темы сайта может быть записана вот так:
DirectoryInfo appThemes = new DirectoryInfo(Page.MapPath("~/App_Themes"));
if(appThemes.GetDirectories().Where(d => d.Name == theme).Count() > 0)
...
Все эти нововведения позволили появиться на свет LINQ (Language Integrated Query).